• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Copyright 2025 The Chromium Authors
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""Run Error Prone."""
7
8import argparse
9import sys
10
11import compile_java
12from util import server_utils
13
14# Add a check here to cause the suggested fix to be applied while compiling.
15# Use this when trying to enable more checks.
16ERRORPRONE_CHECKS_TO_APPLY = []
17
18# Checks to disable in tests.
19TESTONLY_ERRORPRONE_WARNINGS_TO_DISABLE = [
20    # Too much effort to enable.
21    'UnusedVariable',
22    # These are allowed in tests.
23    'NoStreams',
24]
25
26# Full list of checks: https://errorprone.info/bugpatterns
27ERRORPRONE_WARNINGS_TO_DISABLE = [
28    'InlineMeInliner',
29    'InlineMeSuggester',
30    # High priority to enable:
31    'HidingField',
32    'AlreadyChecked',
33    'DirectInvocationOnMock',
34    'MockNotUsedInProduction',
35    # High priority to enable in non-tests:
36    'JdkObsolete',
37    'ReturnValueIgnored',
38    'StaticAssignmentInConstructor',
39    # These are all for Javadoc, which we don't really care about.
40    # vvv
41    'InvalidBlockTag',
42    'InvalidParam',
43    'InvalidLink',
44    'InvalidInlineTag',
45    'MalformedInlineTag',
46    'MissingSummary',
47    'UnescapedEntity',
48    'UnrecognisedJavadocTag',
49    # ^^^
50    'MutablePublicArray',
51    'NonCanonicalType',
52    'DoNotClaimAnnotations',
53    'JavaUtilDate',
54    'IdentityHashMapUsage',
55    'StaticMockMember',
56    # Triggers in tests where this is useful to do.
57    'StaticAssignmentOfThrowable',
58    # TODO(crbug.com/41384349): Follow steps in bug.
59    'CatchAndPrintStackTrace',
60    # TODO(crbug.com/41364806): Follow steps in bug.
61    'TypeParameterUnusedInFormals',
62    # Android platform default is always UTF-8.
63    # https://developer.android.com/reference/java/nio/charset/Charset.html#defaultCharset()
64    'DefaultCharset',
65    # There are lots of times when we just want to post a task.
66    'FutureReturnValueIgnored',
67    # Just false positives in our code.
68    'ThreadJoinLoop',
69    # Low priority corner cases with String.split.
70    # Linking Guava and using Splitter was rejected
71    # in the https://chromium-review.googlesource.com/c/chromium/src/+/871630.
72    'StringSplitter',
73    # Preferred to use another method since it propagates exceptions better.
74    'ClassNewInstance',
75    # Results in false positives.
76    'ThreadLocalUsage',
77    # Low priority.
78    'EqualsHashCode',
79    # Not necessary for tests.
80    'OverrideThrowableToString',
81    # Not that useful.
82    'UnsafeReflectiveConstructionCast',
83    # Not that useful.
84    'MixedMutabilityReturnType',
85    # Nice to have.
86    'EqualsGetClass',
87    # A lot of false-positives from CharSequence.equals().
88    'UndefinedEquals',
89    # Dagger generated code triggers this.
90    'SameNameButDifferent',
91    # Does not apply to Android because it assumes no desugaring.
92    'UnnecessaryLambda',
93    # Nice to have.
94    'EmptyCatch',
95    # Nice to have.
96    'BadImport',
97    # Nice to have.
98    'UseCorrectAssertInTests',
99    # Must be off since we are now passing in annotation processor generated
100    # code as a source jar (deduplicating work with turbine).
101    'RefersToDaggerCodegen',
102    # We already have presubmit checks for this. We don't want it to fail
103    # local compiles.
104    'RemoveUnusedImports',
105    # Only has false positives (would not want to enable this).
106    'UnicodeEscape',
107    # A lot of existing violations. e.g. Should return List and not ArrayList
108    'NonApiType',
109    # Nice to have.
110    'StringCharset',
111    # Nice to have.
112    'StringCaseLocaleUsage',
113    # Low priority.
114    'RedundantControlFlow',
115]
116
117# Full list of checks: https://errorprone.info/bugpatterns
118# Only those marked as "experimental" need to be listed here in order to be
119# enabled.
120ERRORPRONE_WARNINGS_TO_ENABLE = [
121    'BinderIdentityRestoredDangerously',
122    'EmptyIf',
123    'EqualsBrokenForNull',
124    'InvalidThrows',
125    'LongLiteralLowerCaseSuffix',
126    'MultiVariableDeclaration',
127    'RedundantOverride',
128    'StaticQualifiedUsingExpression',
129    'TimeUnitMismatch',
130    'UnnecessaryStaticImport',
131    'UseBinds',
132    'WildcardImport',
133    'NoStreams',
134]
135
136
137def main():
138  parser = argparse.ArgumentParser()
139  parser.add_argument('--skip-build-server',
140                      action='store_true',
141                      help='Avoid using the build server.')
142  parser.add_argument('--use-build-server',
143                      action='store_true',
144                      help='Always use the build server.')
145  parser.add_argument('--testonly',
146                      action='store_true',
147                      help='Disable some Error Prone checks')
148  parser.add_argument('--enable-nullaway',
149                      action='store_true',
150                      help='Enable NullAway (requires --enable-errorprone)')
151  parser.add_argument('--stamp',
152                      required=True,
153                      help='Path of output .stamp file')
154  options, compile_java_argv = parser.parse_known_args()
155
156  compile_java_argv += ['--jar-path', options.stamp]
157
158  # Use the build server for errorprone runs.
159  if not options.skip_build_server and (server_utils.MaybeRunCommand(
160      name=options.stamp,
161      argv=sys.argv,
162      stamp_file=options.stamp,
163      use_build_server=options.use_build_server)):
164    compile_java.main(compile_java_argv, write_depfile_only=True)
165    return
166
167  # All errorprone args are passed space-separated in a single arg.
168  errorprone_flags = ['-Xplugin:ErrorProne']
169
170  if options.enable_nullaway:
171    # See: https://github.com/uber/NullAway/wiki/Configuration
172    # Check nullability only for classes marked with @NullMarked (this is our
173    # migration story).
174    errorprone_flags += ['-XepOpt:NullAway:OnlyNullMarked']
175    errorprone_flags += [
176        '-XepOpt:NullAway:CustomContractAnnotations='
177        'org.chromium.build.annotations.Contract,'
178        'org.chromium.support_lib_boundary.util.Contract'
179    ]
180    # TODO(agrieve): Re-enable once this is fixed:
181    #     https://github.com/uber/NullAway/issues/1104
182    # errorprone_flags += ['-XepOpt:NullAway:CheckContracts=true']
183
184    # Make it a warning to use assumeNonNull() with a @NonNull.
185    errorprone_flags += [('-XepOpt:NullAway:CastToNonNullMethod='
186                          'org.chromium.build.NullUtil.assumeNonNull')]
187    # Detect "assert foo != null" as a null check.
188    errorprone_flags += ['-XepOpt:NullAway:AssertsEnabled=true']
189    # Do not ignore @Nullable & @NonNull in non-@NullMarked classes.
190    errorprone_flags += [
191        '-XepOpt:NullAway:AcknowledgeRestrictiveAnnotations=true'
192    ]
193    # Treat @RecentlyNullable the same as @Nullable.
194    errorprone_flags += ['-XepOpt:Nullaway:AcknowledgeAndroidRecent=true']
195    # Enable experimental checking of @Nullable generics.
196    # https://github.com/uber/NullAway/wiki/JSpecify-Support
197    errorprone_flags += ['-XepOpt:NullAway:JSpecifyMode=true']
198    # Treat these the same as constructors.
199    init_methods = [
200        'android.app.Application.onCreate',
201        'android.app.Activity.onCreate',
202        'android.app.Service.onCreate',
203        'android.app.backup.BackupAgent.onCreate',
204        'android.content.ContentProvider.attachInfo',
205        'android.content.ContentProvider.onCreate',
206        'android.content.ContextWrapper.attachBaseContext',
207        'androidx.preference.PreferenceFragmentCompat.onCreatePreferences',
208    ]
209    errorprone_flags += [
210        '-XepOpt:NullAway:KnownInitializers=' + ','.join(init_methods)
211    ]
212
213  # Make everything a warning so that when treat_warnings_as_errors is false,
214  # they do not fail the build.
215  errorprone_flags += ['-XepAllErrorsAsWarnings']
216  # Don't check generated files (those tagged with @Generated).
217  errorprone_flags += ['-XepDisableWarningsInGeneratedCode']
218  errorprone_flags.extend('-Xep:{}:OFF'.format(x)
219                          for x in ERRORPRONE_WARNINGS_TO_DISABLE)
220  errorprone_flags.extend('-Xep:{}:WARN'.format(x)
221                          for x in ERRORPRONE_WARNINGS_TO_ENABLE)
222  if options.testonly:
223    errorprone_flags.extend('-Xep:{}:OFF'.format(x)
224                            for x in TESTONLY_ERRORPRONE_WARNINGS_TO_DISABLE)
225
226  if ERRORPRONE_CHECKS_TO_APPLY:
227    to_apply = list(ERRORPRONE_CHECKS_TO_APPLY)
228    if options.testonly:
229      to_apply = [
230          x for x in to_apply
231          if x not in TESTONLY_ERRORPRONE_WARNINGS_TO_DISABLE
232      ]
233    errorprone_flags += [
234        '-XepPatchLocation:IN_PLACE', '-XepPatchChecks:,' + ','.join(to_apply)
235    ]
236
237  # These are required to use JDK 16, and are taken directly from
238  # https://errorprone.info/docs/installation
239  javac_args = [
240      '-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED',
241      '-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED',
242      '-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED',
243      '-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED',
244      '-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED',
245      '-J--add-exports=jdk.compiler/com.sun.tools.javac.processing='
246      'ALL-UNNAMED',
247      '-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED',
248      '-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED',
249      '-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED',
250      '-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED',
251  ]
252
253  javac_args += ['-XDcompilePolicy=simple', ' '.join(errorprone_flags)]
254
255  javac_args += ['-XDshould-stop.ifError=FLOW']
256  # This flag quits errorprone after checks and before code generation, since
257  # we do not need errorprone outputs, this speeds up errorprone by 4 seconds
258  # for chrome_java.
259  if not ERRORPRONE_CHECKS_TO_APPLY:
260    javac_args += ['-XDshould-stop.ifNoError=FLOW']
261
262  compile_java.main(compile_java_argv,
263                    extra_javac_args=javac_args,
264                    use_errorprone=True)
265
266
267if __name__ == '__main__':
268  main()
269