pw_presubmit: Add static analyzer presubmit step

Change-Id: Ia4f5f48e4b7e473a9087be1520d6a53c0d0bdaee
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/35402
Commit-Queue: Prashanth Swaminathan <prashanthsw@google.com>
Reviewed-by: Anthony DiGirolamo <tonymd@google.com>
diff --git a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
index 7a25669..5b4b677 100755
--- a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
@@ -20,6 +20,7 @@
 import os
 from pathlib import Path
 import re
+import shutil
 import sys
 from typing import Sequence, IO, Tuple, Optional
 
@@ -516,6 +517,39 @@
         raise PresubmitFailure
 
 
+def static_analysis(ctx: PresubmitContext):
+    """Check that files pass static analyzer checks."""
+    build.gn_gen(ctx.root, ctx.output_dir,
+                 '--export-compile-commands=host_clang_debug')
+    build.ninja(ctx.output_dir, 'host_clang_debug')
+
+    compile_commands = ctx.output_dir.joinpath('compile_commands.json')
+    analyzer_output = ctx.output_dir.joinpath('analyze-build-output')
+
+    if analyzer_output.exists():
+        shutil.rmtree(analyzer_output)
+
+    call('analyze-build',
+         '--cdb',
+         compile_commands,
+         '--exclude',
+         'third_party',
+         '--output',
+         analyzer_output,
+         cwd=ctx.root,
+         env=build.env_with_clang_vars())
+
+    # Search for reports under output directory.
+    reports = list(analyzer_output.glob('*/report*'))
+    if len(reports) != 0:
+        archive = shutil.make_archive(str(analyzer_output), 'zip',
+                                      reports[0].parent)
+        _LOG.error('Static analyzer found errors: %s', archive)
+        _LOG.error('To view report, open: %s',
+                   Path(reports[0]).joinpath('index.html'))
+        raise PresubmitFailure
+
+
 #
 # Presubmit check programs
 #
@@ -533,6 +567,7 @@
     gn_full_qemu_check,
     gn_clang_build,
     gn_gcc_build,
+    static_analysis,
 )
 
 LINTFORMAT = (
diff --git a/pw_presubmit/py/setup.py b/pw_presubmit/py/setup.py
index 959a1d9..0c13568 100644
--- a/pw_presubmit/py/setup.py
+++ b/pw_presubmit/py/setup.py
@@ -22,6 +22,7 @@
     author_email='pigweed-developers@googlegroups.com',
     description='Presubmit tools and a presubmit script for Pigweed',
     install_requires=[
+        'scan-build==2.0.19',
         'yapf==0.30.0',
         'pw_cli',
         'pw_package',