|
44 | 44 |
|
45 | 45 | Here is an example of lint warnings produced by this check:
|
46 | 46 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~text
|
47 |
| -src/test/pkg/LogTest.java:21:Warning: The log call Log.i(...) should be |
| 47 | +src/LogExample.kt:7:Warning: The log call Log.i(...) should be |
48 | 48 | conditional: surround with if (Log.isLoggable(...)) or if
|
49 | 49 | (BuildConfig.DEBUG) { ... } [LogConditional]
|
50 | 50 |
|
51 |
| - Log.i(TAG1, "message" + m); // error: unconditional w/ computation |
52 |
| - -------------------------- |
53 |
| - |
54 |
| - |
55 |
| -src/test/pkg/LogTest.java:22:Warning: The log call Log.i(...) should be |
56 |
| -conditional: surround with if (Log.isLoggable(...)) or if |
57 |
| -(BuildConfig.DEBUG) { ... } [LogConditional] |
58 |
| - |
59 |
| - Log.i(TAG1, toString()); // error: unconditional w/ computation |
| 51 | + Log.i(TAG, "message$m") // string is not constant; computed each time |
60 | 52 | -----------------------
|
61 | 53 |
|
62 | 54 |
|
63 |
| -src/test/pkg/LogTest.java:106:Warning: The log call Log.d(...) should be |
64 |
| -conditional: surround with if (Log.isLoggable(...)) or if |
65 |
| -(BuildConfig.DEBUG) { ... } [LogConditional] |
66 |
| - |
67 |
| - Log.d("Test", "Test" + getClass().toString()); // warn: unconditional |
68 |
| - --------------------------------------------- |
69 |
| - |
70 |
| - |
71 | 55 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
72 | 56 |
|
73 | 57 | Here is the source file referenced above:
|
74 | 58 |
|
75 |
| -`src/test/pkg/LogTest.java`: |
76 |
| -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~java linenumbers |
77 |
| -package test.pkg; |
| 59 | +`src/LogExample.kt`: |
| 60 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~kotlin linenumbers |
| 61 | +import android.util.Log |
78 | 62 |
|
79 |
| -import android.annotation.SuppressLint; |
80 |
| -import android.util.Log; |
81 |
| -import static android.util.Log.DEBUG; |
| 63 | +const val TAG = "tag1" |
82 | 64 |
|
83 |
| -@SuppressWarnings({"UnusedDeclaration", "ClassNameDiffersFromFileName"}) |
84 |
| -public class LogTest { |
85 |
| - private static final String TAG1 = "MyTag1"; |
86 |
| - private static final String TAG2 = "MyTag2"; |
87 |
| - private static final String TAG22 = "1234567890123456789012"; |
88 |
| - private static final String TAG23 = "12345678901234567890123"; |
89 |
| - private static final String TAG24 = "123456789012345678901234"; |
90 |
| - private static final String LONG_TAG = "MyReallyReallyReallyReallyReallyLongTag"; |
91 |
| - |
92 |
| - public void checkConditional(String m) { |
93 |
| - Log.d(TAG1, "message"); // ok: unconditional, but not performing computation |
94 |
| - Log.d(TAG1, m); // ok: unconditional, but not performing computation |
95 |
| - Log.d(TAG1, "ab"); // ok: unconditional, but not performing non-constant computation |
96 |
| - Log.d(TAG1, Constants.MY_MESSAGE); // ok: unconditional, but constant string |
97 |
| - Log.i(TAG1, "message" + m); // error: unconditional w/ computation |
98 |
| - Log.i(TAG1, toString()); // error: unconditional w/ computation |
99 |
| - Log.e(TAG1, toString()); // ok: only flagging debug/info messages |
100 |
| - Log.w(TAG1, toString()); // ok: only flagging debug/info messages |
101 |
| - Log.wtf(TAG1, toString()); // ok: only flagging debug/info messages |
102 |
| - if (Log.isLoggable(TAG1, 0)) { |
103 |
| - Log.d(TAG1, toString()); // ok: conditional |
104 |
| - } |
105 |
| - } |
106 |
| - |
107 |
| - public void checkWrongTag(String tag) { |
108 |
| - if (Log.isLoggable(TAG1, Log.DEBUG)) { |
109 |
| - Log.d(TAG2, "message"); // warn: mismatched tags! |
110 |
| - } |
111 |
| - if (Log.isLoggable("my_tag", Log.DEBUG)) { |
112 |
| - Log.d("other_tag", "message"); // warn: mismatched tags! |
113 |
| - } |
114 |
| - if (Log.isLoggable("my_tag", Log.DEBUG)) { |
115 |
| - Log.d("my_tag", "message"); // ok: strings equal |
116 |
| - } |
117 |
| - if (Log.isLoggable(TAG1, Log.DEBUG)) { |
118 |
| - Log.d(LogTest.TAG1, "message"); // OK: same tag; different access syntax |
119 |
| - } |
120 |
| - if (Log.isLoggable(tag, Log.DEBUG)) { |
121 |
| - Log.d(tag, "message"); // ok: same variable |
122 |
| - } |
123 |
| - } |
124 |
| - |
125 |
| - public void checkLongTag(boolean shouldLog) { |
126 |
| - if (shouldLog) { |
127 |
| - // String literal tags |
128 |
| - Log.d("short_tag", "message"); // ok: short |
129 |
| - Log.d("really_really_really_really_really_long_tag", "message"); // error: too long |
130 |
| - |
131 |
| - // Resolved field tags |
132 |
| - Log.d(TAG1, "message"); // ok: short |
133 |
| - Log.d(TAG22, "message"); // ok: short |
134 |
| - Log.d(TAG23, "message"); // ok: threshold |
135 |
| - Log.d(TAG24, "message"); // error: too long |
136 |
| - Log.d(LONG_TAG, "message"); // error: way too long |
137 |
| - |
138 |
| - // Locally defined variable tags |
139 |
| - final String LOCAL_TAG = "MyReallyReallyReallyReallyReallyLongTag"; |
140 |
| - Log.d(LOCAL_TAG, "message"); // error: too long |
141 |
| - |
142 |
| - // Concatenated tags |
143 |
| - Log.d(TAG22 + TAG1, "message"); // error: too long |
144 |
| - Log.d(TAG22 + "MyTag", "message"); // error: too long |
145 |
| - } |
146 |
| - } |
147 |
| - |
148 |
| - public void checkWrongLevel(String tag) { |
149 |
| - if (Log.isLoggable(TAG1, Log.DEBUG)) { |
150 |
| - Log.d(TAG1, "message"); // ok: right level |
151 |
| - } |
152 |
| - if (Log.isLoggable(TAG1, Log.INFO)) { |
153 |
| - Log.i(TAG1, "message"); // ok: right level |
154 |
| - } |
155 |
| - if (Log.isLoggable(TAG1, Log.DEBUG)) { |
156 |
| - Log.v(TAG1, "message"); // warn: wrong level |
157 |
| - } |
158 |
| - if (Log.isLoggable(TAG1, DEBUG)) { // static import of level |
159 |
| - Log.v(TAG1, "message"); // warn: wrong level |
160 |
| - } |
161 |
| - if (Log.isLoggable(TAG1, Log.VERBOSE)) { |
162 |
| - Log.d(TAG1, "message"); // warn? verbose is a lower logging level, which includes debug |
163 |
| - } |
164 |
| - if (Log.isLoggable(TAG1, Constants.MY_LEVEL)) { |
165 |
| - Log.d(TAG1, "message"); // ok: unknown level alias |
166 |
| - } |
167 |
| - } |
168 |
| - |
169 |
| - @SuppressLint("all") |
170 |
| - public void suppressed1() { |
171 |
| - Log.d(TAG1, "message"); // ok: suppressed |
172 |
| - } |
173 |
| - |
174 |
| - @SuppressLint("LogConditional") |
175 |
| - public void suppressed2() { |
176 |
| - Log.d(TAG1, "message"); // ok: suppressed |
177 |
| - } |
178 |
| - |
179 |
| - // Regression test for https://issuetracker.google.com/111063607 |
180 |
| - public void notActuallyConditional() { |
181 |
| - if (true) { |
182 |
| - Log.d("Test", "Test" + getClass().toString()); // warn: unconditional |
183 |
| - } |
184 |
| - if (false) { |
185 |
| - Log.d("Test", "Test" + getClass().toString()); // ok: never called |
186 |
| - } |
187 |
| - } |
188 |
| - |
189 |
| - private static class Constants { |
190 |
| - public static final String MY_MESSAGE = "My Message"; |
191 |
| - public static final int MY_LEVEL = 5; |
| 65 | +class LogExample { |
| 66 | + fun test(m: String) { |
| 67 | + Log.i(TAG, "message$m") // string is not constant; computed each time |
192 | 68 | }
|
193 | 69 | }
|
194 | 70 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
197 | 73 | [source code](https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-master-dev:lint/libs/lint-tests/src/test/java/com/android/tools/lint/checks/LogDetectorTest.kt)
|
198 | 74 | for the unit tests for this check to see additional scenarios.
|
199 | 75 |
|
200 |
| -The above example was automatically extracted from the first unit test |
201 |
| -found for this lint check, `LogDetector.testBasic`. |
202 |
| -To report a problem with this extracted sample, visit |
203 |
| -https://issuetracker.google.com/issues/new?component=192708. |
204 |
| - |
205 | 76 | (##) Suppressing
|
206 | 77 |
|
207 | 78 | You can suppress false positives using one of the following mechanisms:
|
|
0 commit comments