|
| 1 | +<meta charset="utf-8" lang="kotlin"> |
| 2 | + |
| 3 | +# Error Message Conventions |
| 4 | + |
| 5 | +## Length |
| 6 | + |
| 7 | +The error message reported by a detector should typically be short; think of |
| 8 | +typical compiler error messages you see from `kotlinc` or `javac`. |
| 9 | + |
| 10 | +This is particularly important when your lint check is running inside the IDE, |
| 11 | +because the error message will typically be shown as a tooltip as the user |
| 12 | +hovers over the underlined symbol. |
| 13 | + |
| 14 | +It's tempting to try to fully explain what's going on, but lint has separate |
| 15 | +facilities for that -- the issue explanation metadata. When lint generates text |
| 16 | +and html reports, it will include the explanation metadata. Similarly, in the |
| 17 | +IDE, users can pull up the full explanation with a tooltip. |
| 18 | + |
| 19 | +This is not a hard rule; there are cases where lint uses multiple sentences to |
| 20 | +explain an issue, but strive to make the error message as short as possible |
| 21 | +while still legible. |
| 22 | + |
| 23 | +## Formatting |
| 24 | + |
| 25 | +Use the available formatting support for text in lint: |
| 26 | + |
| 27 | +Raw text format | Renders To |
| 28 | +-----------------------------|-------------------------- |
| 29 | +This is a \`code symbol\` | This is a `code symbol` |
| 30 | +This is `*italics*` | This is *italics* |
| 31 | +This is `**bold**` | This is **bold** |
| 32 | +http://, https:// | [](http://), [](https://) |
| 33 | +`\*not italics*` | `\*not italics*` |
| 34 | +\`\`\`language\n text\n\`\`\`| (preformatted text block) |
| 35 | + [Supported markup in lint's markdown-like raw text format] |
| 36 | + |
| 37 | +In particular, when referencing code elements such as variable names, APIs, and |
| 38 | +so on, use the code symbol formatting (\`like this\`), not simple or double |
| 39 | +quotes. |
| 40 | + |
| 41 | +## Punctuation |
| 42 | + |
| 43 | +One line error messages should not be punctuated - e.g. the error message |
| 44 | +should be “Unused import foo”, not “Unused import foo.” |
| 45 | + |
| 46 | +However, if there are multiple sentences in the error message, all sentences |
| 47 | +should be punctuate. |
| 48 | + |
| 49 | +Note that there should be no space before an exclamation (!) or question mark |
| 50 | +(?) sign. |
| 51 | + |
| 52 | +## Include Details |
| 53 | + |
| 54 | +Avoid generic error messages such as “Unused import”; try to incorporate |
| 55 | +specific details from the current error. In the unused import example, instead |
| 56 | +of just saying “Unused import”, say “Unused import java.io.List”. |
| 57 | + |
| 58 | +In addition to being clearer (you can see from the error message what the |
| 59 | +problem is without having to look up the corresponding source code), this is |
| 60 | +important to support lint's [baseline](../usage/baselines.md.html) feature. |
| 61 | +Lint matches known errors not by matching on specific line numbers (which would |
| 62 | +cause problems as soon as the line numbers drift after edits to the file), lint |
| 63 | +matches by error message in the file, so the more unique error messages are, |
| 64 | +the better. If all unused import warnings were just “Unused import”, lint would |
| 65 | +match them in order, which often would be the wrong thing. |
| 66 | + |
| 67 | +## Reference Android By Number |
| 68 | + |
| 69 | +When referring to Android behaviors introduced in new API levels, use the |
| 70 | +phrase “In Android 12 and higher”, instead of variations like “Android S” or |
| 71 | +"API 31“. |
| 72 | + |
| 73 | +## Keep Messages Stable |
| 74 | + |
| 75 | +Once you have written an error message, think twice before changing it. This is |
| 76 | +again because of the baseline mechanism mentioned above. If users have already |
| 77 | +run lint with your previous error message, and that message has been written |
| 78 | +into baselines, changing the error message will cause the baseline to no longer |
| 79 | +match, which means this will show up as a new error for users. |
| 80 | + |
| 81 | +If you **have** to change an error message because it's misleading, then of |
| 82 | +course, do that -- but avoid it if there isn't a strong reason to do so. |
| 83 | + |
| 84 | +There *are* some edits you can make to the error message which the baseline |
| 85 | +matcher will handle: |
| 86 | + |
| 87 | +* Adding a suffix |
| 88 | +* Adding a suffix which also changes the final punctuation; e.g. changing |
| 89 | + ”Hello.“ to ”Hello, world!“ is compatible. |
| 90 | +* Adding a prefix |
| 91 | + |
| 92 | +## Examples |
| 93 | + |
| 94 | +Here are some examples from lint's built-in checks. Note that these are not |
| 95 | +chosen as great examples of clear error messages; most of these were written |
| 96 | +by engineers without review from a tech writer. But for better or worse they |
| 97 | +reflect the ”tone“ of the built-in lint checks today. (These were derived from |
| 98 | +lint's unit test suite, which explains silly symbols like `test.pkg` in the |
| 99 | +error messages.) |
| 100 | + |
| 101 | +Note that the [Id] block is not part of the error message; it's included here |
| 102 | +to help cross reference the messages with the corresponding lint check. |
| 103 | + |
| 104 | +* [AccidentalOctal] The leading 0 turns this number into octal which is probably not what was intended (interpreted as 8) |
| 105 | +* [AdapterViewChildren] A list/grid should have no children declared in XML |
| 106 | +* [AddJavascriptInterface] \`WebView.addJavascriptInterface\` should not be called with minSdkVersion < 17 for security reasons: JavaScript can use reflection to manipulate application |
| 107 | +* [AllCaps] Using \`textAllCaps\` with a string (\`has_markup\`) that contains markup; the markup will be dropped by the caps conversion |
| 108 | +* [AllowAllHostnameVerifier] Using the \`AllowAllHostnameVerifier\` HostnameVerifier is unsafe because it always returns true, which could cause insecure network traffic due to trusting TLS/SSL server certificates for wrong hostnames |
| 109 | +* [AlwaysShowAction] Prefer \`ifRoom\` instead of \`always\` |
| 110 | +* [AndroidGradlePluginVersion] A newer version of com.android.tools.build:gradle than 3.3.0-alpha04 is available: 3.3.2 |
| 111 | +* [AnimatorKeep] This method is accessed from an ObjectAnimator so it should be annotated with \`@Keep\` to ensure that it is not discarded or renamed in release builds |
| 112 | +* [AnnotateVersionCheck] This field should be annotated with \`ChecksSdkIntAtLeast(api=Build.VERSION_CODES.LOLLIPOP)\` |
| 113 | +* [AnnotationProcessorOnCompilePath] Add annotation processor to processor path using \`annotationProcessor\` instead of \`api\` |
| 114 | +* [AppBundleLocaleChanges] Found dynamic locale changes, but did not find corresponding Play Core library calls for downloading languages and splitting by language is not disabled in the \`bundle\` configuration |
| 115 | +* [AppCompatCustomView] This custom view should extend \`android.support.v7.widget.AppCompatButton\` instead |
| 116 | +* [AppCompatMethod] Should use \`getSupportActionBar\` instead of \`getActionBar\` name |
| 117 | +* [AppCompatResource] Should use \`android:showAsAction\` when not using the appcompat library |
| 118 | +* [AppIndexingService] \`UPDATE_INDEX\` is configured as a service in your app, which is no longer supported for the API level you're targeting. Use a \`BroadcastReceiver\` instead. |
| 119 | +* [AppLinkUrlError] Missing URL for the intent filter |
| 120 | +* [AppLinksAutoVerify] This host does not support app links to your app. Checks the Digital Asset Links JSON file: http://example.com/.well-known/assetlinks.json |
| 121 | +* [ApplySharedPref] Consider using \`apply()\` instead; \`commit\` writes its data to persistent storage immediately, whereas \`apply\` will handle it in the background |
| 122 | +* [AssertionSideEffect] Assertion condition has a side effect: i++ |
| 123 | +* [Autofill] Missing \`autofillHints\` attribute |
| 124 | +* [BackButton] Back buttons are not standard on Android; see design guide's navigation section |
| 125 | +* [BadHostnameVerifier] \`verify\` always returns \`true\`, which could cause insecure network traffic due to trusting TLS/SSL server certificates for wrong hostnames |
| 126 | +* [BatteryLife] Use of \`com.android.camera.NEW_PICTURE\` is deprecated for all apps starting with the N release independent of the target SDK. Apps should not rely on these broadcasts and instead use \`WorkManager\` |
| 127 | +* [BidiSpoofing] Comment contains misleading Unicode bidirectional text |
| 128 | +* [BlockedPrivateApi] Reflective access to NETWORK_TYPES is forbidden when targeting API 28 and above |
| 129 | +* [BottomAppBar] This \`BottomAppBar\` must be wrapped in a \`CoordinatorLayout\` (\`android.support.design.widget.CoordinatorLayout\`) |
| 130 | +* [BrokenIterator] \`Vector#listIterator\` was broken in API 24 and 25; it can return \`hasNext()=false\` before the last element. Consider switching to \`ArrayList\` with synchronization if you need it. |
| 131 | +* [ButtonCase] @android:string/yes actually returns ”OK“, not ”Yes“; use @android:string/ok instead or create a local string resource for Yes |
| 132 | +* [ButtonOrder] OK button should be on the right (was ”OK | Cancel“, should be ”Cancel | OK“) |
| 133 | +* [ButtonStyle] Buttons in button bars should be borderless; use \`style="?android:attr/buttonBarButtonStyle"\` (and \`?android:attr/buttonBarStyle\` on the parent) |
| 134 | +* [ByteOrderMark] Found byte-order-mark in the middle of a file |
| 135 | +* [CanvasSize] Calling \`Canvas.getWidth()\` is usually wrong; you should be calling \`getWidth()\` instead |
| 136 | +* [CheckResult] The result of \`double\` is not used |
| 137 | +* [ClickableViewAccessibility] Custom view \`\`NoPerformClick\`\` has \`setOnTouchListener\` called on it but does not override \`performClick\` |
| 138 | +* [CoarseFineLocation] If you need access to FINE location, you must request both \`ACCESS_FINE_LOCATION\` and \`ACCESS_COARSE_LOCATION\` |
| 139 | +* [CommitPrefEdits] \`SharedPreferences.edit()\` without a corresponding \`commit()\` or \`apply()\` call |
| 140 | +* [CommitTransaction] This transaction should be completed with a \`commit()\` call |
| 141 | +* [ConstantLocale] Assigning \`Locale.getDefault()\` to a final static field is suspicious; this code will not work correctly if the user changes locale while the app is running |
| 142 | +* [ContentDescription] Missing \`contentDescription\` attribute on image |
| 143 | +* [ConvertToWebp] One or more images in this project can be converted to the WebP format which typically results in smaller file sizes, even for lossless conversion |
| 144 | +* [CustomPermissionTypo] Did you mean \`my.custom.permission.FOOBAR\`? |
| 145 | +* [CustomSplashScreen] The application should not provide its own launch screen |
| 146 | +* [CustomViewStyleable] By convention, the custom view (\`CustomView1\`) and the declare-styleable (\`MyDeclareStyleable\`) should have the same name (various editor features rely on this convention) |
| 147 | +* [CustomX509TrustManager] Implementing a custom \`X509TrustManager\` is error-prone and likely to be insecure. It is likely to disable certificate validation altogether, and is non-trivial to implement correctly without calling Android's default implementation. |
| 148 | +* [CutPasteId] The id \`R.id.duplicated\` has already been looked up in this method; possible cut & paste error? |
| 149 | +* [DalvikOverride] This package private method may be unintentionally overriding \`method\` in \`pkg1.Class1\` |
| 150 | +* [DataBindingWithoutKapt] If you plan to use data binding in a Kotlin project, you should apply the kotlin-kapt plugin. |
| 151 | +* [DataExtractionRules] The attribute \`android:allowBackup\` is deprecated from Android 12 and the default allows backup |
| 152 | +* [DefaultEncoding] This \`Scanner\` will use the default system encoding instead of a specific charset which is usually a mistake; add charset argument, \`Scanner(..., UTF_8)\`? |
| 153 | +* [DefaultLocale] Implicitly using the default locale is a common source of bugs: Use \`toUpperCase(Locale)\` instead. For strings meant to be internal use \`Locale.ROOT\`, otherwise \`Locale.getDefault()\`. |
| 154 | +* [DeletedProvider] The Crypto provider has been deleted in Android P (and was deprecated in Android N), so the code will crash |
| 155 | +* [DeprecatedProvider] The \`BC\` provider is deprecated and when \`targetSdkVersion\` is moved to \`P\` this method will throw a \`NoSuchAlgorithmException\`. To fix this you should stop specifying a provider and use the default implementation |
| 156 | +* [DeprecatedSinceApi] This method is deprecated as of API level 25 |
| 157 | +* [Deprecated] \`AbsoluteLayout\` is deprecated |
| 158 | +* [DevModeObsolete] You no longer need a \`dev\` mode to enable multi-dexing during development, and this can break API version checks |
| 159 | +* [DeviceAdmin] You must have an intent filter for action \`android.app.action.DEVICE_ADMIN_ENABLED\` |
| 160 | +* [DiffUtilEquals] Suspicious equality check: Did you mean \`.equals()\` instead of \`==\` ? |
| 161 | +* [DisableBaselineAlignment] Set \`android:baselineAligned="false"\` on this element for better performance |
| 162 | +* [DiscouragedPrivateApi] Reflective access to addAssetPath, which is not part of the public SDK and therefore likely to change in future Android releases |
| 163 | +* [DrawAllocation] Avoid object allocations during draw/layout operations (preallocate and reuse instead) |
| 164 | +* [DuplicateActivity] Duplicate registration for activity \`com.example.helloworld.HelloWorld\` |
| 165 | +* [DuplicateDefinition] \`app_name\` has already been defined in this folder |
| 166 | +* [DuplicateDivider] Replace with \`android.support.v7.widget.DividerItemDecoration\`? |
| 167 | +* [DuplicateIds] Duplicate id \`@+id/android_logo\`, already defined earlier in this layout |
| 168 | +* [DuplicateIncludedIds] Duplicate id @+id/button1, defined or included multiple times in layout/layout2.xml: * [layout/layout2.xml => layout/layout3.xml defines @+id/button1, layout/layout2.xml => layout/layout4.xml defines @+id/button1] |
| 169 | +* [DuplicatePlatformClasses] \`xpp3\` defines classes that conflict with classes now provided by Android. Solutions include finding newer versions or alternative libraries that don't have the same problem (for example, for \`httpclient\` use \`HttpUrlConnection\` or \`okhttp\` instead), or repackaging the library using something like \`jarjar\`. |
| 170 | +* [DuplicateStrings] Duplicate string value \`HELLO\`, used in \`hello_caps\` and \`hello\`. Use \`android:inputType\` or \`android:capitalize\` to treat these as the same and avoid string duplication. |
| 171 | +* [DuplicateUsesFeature] Duplicate declaration of uses-feature \`android.hardware.camera\` |
| 172 | +* [EllipsizeMaxLines] Combining \`ellipsize=start\` and \`lines=1\` can lead to crashes. Use \`singleLine=true\` instead. |
| 173 | +* [EmptySuperCall] No need to call \`super.someOtherMethod\`; the super method is defined to be empty |
| 174 | +* [EnforceUTF8] iso-latin-1: Not using UTF-8 as the file encoding. This can lead to subtle bugs with non-ascii characters |
| 175 | +* [EnqueueWork] WorkContinuation \`cont\` not enqueued: did you forget to call \`enqueue()\`? |
| 176 | + |
| 177 | +<!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="markdeep.min.js" charset="utf-8"></script><script src="https://morgan3d.github.io/markdeep/latest/markdeep.min.js" charset="utf-8"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script> |
0 commit comments