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