[clang] d9cf829 - Create install targets for scan-build-py.

Marco Vanotti via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 21 13:08:45 PDT 2021


Author: Daniel Hwang
Date: 2021-06-21T13:08:34-07:00
New Revision: d9cf8291e7ef26317c13ed9a4e9bd88855166d5d

URL: https://github.com/llvm/llvm-project/commit/d9cf8291e7ef26317c13ed9a4e9bd88855166d5d
DIFF: https://github.com/llvm/llvm-project/commit/d9cf8291e7ef26317c13ed9a4e9bd88855166d5d.diff

LOG: Create install targets for scan-build-py.

A new revision identical to https://reviews.llvm.org/D101139
The parent revision of aforementioned revision seems to cause pre-merge checks to fail opaquely. Seeing if creating a new revision will work.

Reviewed By: phosek

Differential Revision: https://reviews.llvm.org/D104138

Added: 
    clang/tools/scan-build-py/CMakeLists.txt
    clang/tools/scan-build-py/lib/libear/__init__.py
    clang/tools/scan-build-py/lib/libear/config.h.in
    clang/tools/scan-build-py/lib/libear/ear.c
    clang/tools/scan-build-py/lib/libscanbuild/__init__.py
    clang/tools/scan-build-py/lib/libscanbuild/analyze.py
    clang/tools/scan-build-py/lib/libscanbuild/arguments.py
    clang/tools/scan-build-py/lib/libscanbuild/clang.py
    clang/tools/scan-build-py/lib/libscanbuild/compilation.py
    clang/tools/scan-build-py/lib/libscanbuild/intercept.py
    clang/tools/scan-build-py/lib/libscanbuild/report.py
    clang/tools/scan-build-py/lib/libscanbuild/resources/scanview.css
    clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
    clang/tools/scan-build-py/lib/libscanbuild/resources/sorttable.js
    clang/tools/scan-build-py/lib/libscanbuild/shell.py
    clang/tools/scan-build-py/libexec/analyze-c++
    clang/tools/scan-build-py/libexec/analyze-cc
    clang/tools/scan-build-py/libexec/intercept-c++
    clang/tools/scan-build-py/libexec/intercept-cc

Modified: 
    clang/cmake/caches/Fuchsia-stage2.cmake
    clang/tools/CMakeLists.txt
    clang/tools/scan-build-py/bin/analyze-build
    clang/tools/scan-build-py/bin/intercept-build
    clang/tools/scan-build-py/bin/scan-build
    clang/tools/scan-build-py/tests/__init__.py
    clang/tools/scan-build-py/tests/functional/cases/__init__.py
    clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
    clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
    clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
    clang/tools/scan-build-py/tests/unit/test_analyze.py

Removed: 
    clang/tools/scan-build-py/bin/analyze-c++
    clang/tools/scan-build-py/bin/analyze-cc
    clang/tools/scan-build-py/bin/intercept-c++
    clang/tools/scan-build-py/bin/intercept-cc
    clang/tools/scan-build-py/libear/__init__.py
    clang/tools/scan-build-py/libear/config.h.in
    clang/tools/scan-build-py/libear/ear.c
    clang/tools/scan-build-py/libscanbuild/__init__.py
    clang/tools/scan-build-py/libscanbuild/analyze.py
    clang/tools/scan-build-py/libscanbuild/arguments.py
    clang/tools/scan-build-py/libscanbuild/clang.py
    clang/tools/scan-build-py/libscanbuild/compilation.py
    clang/tools/scan-build-py/libscanbuild/intercept.py
    clang/tools/scan-build-py/libscanbuild/report.py
    clang/tools/scan-build-py/libscanbuild/resources/scanview.css
    clang/tools/scan-build-py/libscanbuild/resources/selectable.js
    clang/tools/scan-build-py/libscanbuild/shell.py


################################################################################
diff  --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake
index 85d96bc52d529..eb001ef6579ce 100644
--- a/clang/cmake/caches/Fuchsia-stage2.cmake
+++ b/clang/cmake/caches/Fuchsia-stage2.cmake
@@ -291,6 +291,7 @@ set(LLVM_TOOLCHAIN_TOOLS
   llvm-symbolizer
   llvm-xray
   sancov
+  scan-build-py
   CACHE STRING "")
 
 set(LLVM_DISTRIBUTION_COMPONENTS

diff  --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt
index 63fe79eccf732..c929f6e665e2c 100644
--- a/clang/tools/CMakeLists.txt
+++ b/clang/tools/CMakeLists.txt
@@ -32,6 +32,7 @@ if(CLANG_ENABLE_STATIC_ANALYZER)
   add_clang_subdirectory(clang-check)
   add_clang_subdirectory(clang-extdef-mapping)
   add_clang_subdirectory(scan-build)
+  add_clang_subdirectory(scan-build-py)
   add_clang_subdirectory(scan-view)
 endif()
 

diff  --git a/clang/tools/scan-build-py/CMakeLists.txt b/clang/tools/scan-build-py/CMakeLists.txt
new file mode 100644
index 0000000000000..c9f1cb7d6b2a7
--- /dev/null
+++ b/clang/tools/scan-build-py/CMakeLists.txt
@@ -0,0 +1,132 @@
+set (BinFiles
+     "analyze-build"
+     "intercept-build"
+     "scan-build")
+
+set (LibExecs
+     "analyze-c++"
+     "analyze-cc"
+     "intercept-c++"
+     "intercept-cc")
+
+set (LibScanbuild
+     "__init__.py"
+     "analyze.py"
+     "arguments.py"
+     "clang.py"
+     "compilation.py"
+     "intercept.py"
+     "report.py"
+     "shell.py")
+
+set (LibScanbuildResources
+     "scanview.css"
+     "selectable.js"
+     "sorttable.js")
+
+# libear is compiled dynamically in build_libear using the specified cc
+# compiler.
+set (LibEar
+     "__init__.py"
+     "config.h.in"
+     "ear.c")
+
+foreach(BinFile ${BinFiles})
+  if ("${BinFile}" STREQUAL "scan-build")
+    # Need to rename scan-build to scan-build-py to prevent overwriting
+    # scan-build Perl implementation.
+    add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/scan-build-py
+                       COMMAND ${CMAKE_COMMAND} -E make_directory
+                         ${CMAKE_BINARY_DIR}/bin
+                       COMMAND ${CMAKE_COMMAND} -E copy
+                         ${CMAKE_CURRENT_SOURCE_DIR}/bin/scan-build
+                         ${CMAKE_BINARY_DIR}/bin/scan-build-py
+                       DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/scan-build)
+    install (PROGRAMS "bin/scan-build"
+             DESTINATION bin
+             RENAME scan-build-py
+             COMPONENT scan-build-py)
+    list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/scan-build-py)
+  else()
+    add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile}
+                       COMMAND ${CMAKE_COMMAND} -E make_directory
+                         ${CMAKE_BINARY_DIR}/bin
+                       COMMAND ${CMAKE_COMMAND} -E copy
+                         ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}
+                         ${CMAKE_BINARY_DIR}/bin/
+                       DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile})
+    install(PROGRAMS bin/${BinFile}
+            DESTINATION bin
+            COMPONENT scan-build-py)
+    list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile})
+  endif()
+endforeach()
+
+foreach(lib ${LibExecs})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/libexec/${lib}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/libexec
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${lib}
+                       ${CMAKE_BINARY_DIR}/libexec/
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${lib})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${lib})
+  install(PROGRAMS libexec/${lib}
+          DESTINATION libexec
+          COMPONENT scan-build-py)
+endforeach()
+
+foreach(lib ${LibScanbuild})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libscanbuild/${lib}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/${lib}
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild/
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/${lib})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/${lib})
+  install(PROGRAMS lib/libscanbuild/${lib}
+          DESTINATION lib/libscanbuild
+          COMPONENT scan-build-py)
+endforeach()
+
+foreach(resource ${LibScanbuildResources})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources/${resource}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/resources/${resource}
+                       ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libscanbuild/resources/${resource})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libscanbuild/resources/${resource})
+  install(PROGRAMS lib/libscanbuild/resources/${resource}
+          DESTINATION lib/libscanbuild/resources
+          COMPONENT scan-build-py)
+endforeach()
+
+foreach(lib ${LibEar})
+  add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/libear/${lib}
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib
+                     COMMAND ${CMAKE_COMMAND} -E make_directory
+                       ${CMAKE_BINARY_DIR}/lib/libear
+                     COMMAND ${CMAKE_COMMAND} -E copy
+                       ${CMAKE_CURRENT_SOURCE_DIR}/lib/libear/${lib}
+                       ${CMAKE_BINARY_DIR}/lib/libear/
+                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/lib/libear/${lib})
+  list(APPEND Depends ${CMAKE_BINARY_DIR}/lib/libear/${lib})
+  install(PROGRAMS lib/libear/${lib}
+          DESTINATION lib/libear
+          COMPONENT scan-build-py)
+endforeach()
+
+add_custom_target(scan-build-py ALL DEPENDS ${Depends})
+add_llvm_install_targets("install-scan-build-py"
+                         DEPENDS scan-build-py
+                         COMPONENT scan-build-py)

diff  --git a/clang/tools/scan-build-py/bin/analyze-build b/clang/tools/scan-build-py/bin/analyze-build
index 0884ef2234bf4..b3f61429906c4 100755
--- a/clang/tools/scan-build-py/bin/analyze-build
+++ b/clang/tools/scan-build-py/bin/analyze-build
@@ -8,7 +8,7 @@ import multiprocessing
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.analyze import analyze_build
 

diff  --git a/clang/tools/scan-build-py/bin/intercept-build b/clang/tools/scan-build-py/bin/intercept-build
index d9757b77b5c73..9ecde39984434 100755
--- a/clang/tools/scan-build-py/bin/intercept-build
+++ b/clang/tools/scan-build-py/bin/intercept-build
@@ -8,7 +8,7 @@ import multiprocessing
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.intercept import intercept_build
 

diff  --git a/clang/tools/scan-build-py/bin/scan-build b/clang/tools/scan-build-py/bin/scan-build
index be4e51887e30b..a341751d993a2 100755
--- a/clang/tools/scan-build-py/bin/scan-build
+++ b/clang/tools/scan-build-py/bin/scan-build
@@ -8,7 +8,7 @@ import multiprocessing
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.analyze import scan_build
 

diff  --git a/clang/tools/scan-build-py/libear/__init__.py b/clang/tools/scan-build-py/lib/libear/__init__.py
similarity index 100%
rename from clang/tools/scan-build-py/libear/__init__.py
rename to clang/tools/scan-build-py/lib/libear/__init__.py

diff  --git a/clang/tools/scan-build-py/libear/config.h.in b/clang/tools/scan-build-py/lib/libear/config.h.in
similarity index 100%
rename from clang/tools/scan-build-py/libear/config.h.in
rename to clang/tools/scan-build-py/lib/libear/config.h.in

diff  --git a/clang/tools/scan-build-py/lib/libear/ear.c b/clang/tools/scan-build-py/lib/libear/ear.c
new file mode 100644
index 0000000000000..b06ec7ab00040
--- /dev/null
+++ b/clang/tools/scan-build-py/lib/libear/ear.c
@@ -0,0 +1,601 @@
+/* -*- coding: utf-8 -*-
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+*/
+
+/**
+ * This file implements a shared library. This library can be pre-loaded by
+ * the dynamic linker of the Operating System (OS). It implements a few function
+ * related to process creation. By pre-load this library the executed process
+ * uses these functions instead of those from the standard library.
+ *
+ * The idea here is to inject a logic before call the real methods. The logic is
+ * to dump the call into a file. To call the real method this library is doing
+ * the job of the dynamic linker.
+ *
+ * The only input for the log writing is about the destination directory.
+ * This is passed as environment variable.
+ */
+
+// NOLINTNEXTLINE
+#include "config.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
+#include <spawn.h>
+#endif
+
+#if defined HAVE_NSGETENVIRON
+#include <crt_externs.h>
+#else
+extern char **environ;
+#endif
+
+#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
+#ifdef APPLE
+#define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
+#define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
+#define ENV_SIZE 3
+#else
+#define ENV_PRELOAD "LD_PRELOAD"
+#define ENV_SIZE 2
+#endif
+
+#define DLSYM(TYPE_, VAR_, SYMBOL_)                                            \
+  union {                                                                      \
+    void *from;                                                                \
+    TYPE_ to;                                                                  \
+  } cast;                                                                      \
+  if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) {                          \
+    perror("bear: dlsym");                                                     \
+    exit(EXIT_FAILURE);                                                        \
+  }                                                                            \
+  TYPE_ const VAR_ = cast.to;
+
+typedef char const *bear_env_t[ENV_SIZE];
+
+static int bear_capture_env_t(bear_env_t *env);
+static int bear_reset_env_t(bear_env_t *env);
+static void bear_release_env_t(bear_env_t *env);
+static char const **bear_update_environment(char *const envp[],
+                                            bear_env_t *env);
+static char const **bear_update_environ(char const **in, char const *key,
+                                        char const *value);
+static char **bear_get_environment();
+static void bear_report_call(char const *fun, char const *const argv[]);
+static char const **bear_strings_build(char const *arg, va_list *ap);
+static char const **bear_strings_copy(char const **const in);
+static char const **bear_strings_append(char const **in, char const *e);
+static size_t bear_strings_length(char const *const *in);
+static void bear_strings_release(char const **);
+
+static bear_env_t env_names = {ENV_OUTPUT, ENV_PRELOAD
+#ifdef ENV_FLAT
+                               ,
+                               ENV_FLAT
+#endif
+};
+
+static bear_env_t initial_env = {0, 0
+#ifdef ENV_FLAT
+                                 ,
+                                 0
+#endif
+};
+
+static int initialized = 0;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void on_load(void) __attribute__((constructor));
+static void on_unload(void) __attribute__((destructor));
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+                       char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]);
+#endif
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+                        char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+                       char *const argv[]);
+#endif
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[], char *const envp[]);
+#endif
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+                            const posix_spawn_file_actions_t *file_actions,
+                            const posix_spawnattr_t *restrict attrp,
+                            char *const argv[restrict],
+                            char *const envp[restrict]);
+#endif
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+                             const posix_spawn_file_actions_t *file_actions,
+                             const posix_spawnattr_t *restrict attrp,
+                             char *const argv[restrict],
+                             char *const envp[restrict]);
+#endif
+
+/* Initialization method to Captures the relevant environment variables.
+ */
+
+static void on_load(void) {
+  pthread_mutex_lock(&mutex);
+  if (!initialized)
+    initialized = bear_capture_env_t(&initial_env);
+  pthread_mutex_unlock(&mutex);
+}
+
+static void on_unload(void) {
+  pthread_mutex_lock(&mutex);
+  bear_release_env_t(&initial_env);
+  initialized = 0;
+  pthread_mutex_unlock(&mutex);
+}
+
+/* These are the methods we are try to hijack.
+ */
+
+#ifdef HAVE_EXECVE
+int execve(const char *path, char *const argv[], char *const envp[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECV
+#ifndef HAVE_EXECVE
+#error can not implement execv without execve
+#endif
+int execv(const char *path, char *const argv[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  char *const *envp = bear_get_environment();
+  return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+int execvpe(const char *file, char *const argv[], char *const envp[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execvpe(file, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVP
+int execvp(const char *file, char *const argv[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execvp(file, argv);
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+int execvP(const char *file, const char *search_path, char *const argv[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_execvP(file, search_path, argv);
+}
+#endif
+
+#ifdef HAVE_EXECT
+int exect(const char *path, char *const argv[], char *const envp[]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_exect(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECL
+#ifndef HAVE_EXECVE
+#error can not implement execl without execve
+#endif
+int execl(const char *path, const char *arg, ...) {
+  va_list args;
+  va_start(args, arg);
+  char const **argv = bear_strings_build(arg, &args);
+  va_end(args);
+
+  bear_report_call(__func__, (char const *const *)argv);
+  char *const *envp = bear_get_environment();
+  int const result = call_execve(path, (char *const *)argv, envp);
+
+  bear_strings_release(argv);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECLP
+#ifndef HAVE_EXECVP
+#error can not implement execlp without execvp
+#endif
+int execlp(const char *file, const char *arg, ...) {
+  va_list args;
+  va_start(args, arg);
+  char const **argv = bear_strings_build(arg, &args);
+  va_end(args);
+
+  bear_report_call(__func__, (char const *const *)argv);
+  int const result = call_execvp(file, (char *const *)argv);
+
+  bear_strings_release(argv);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECLE
+#ifndef HAVE_EXECVE
+#error can not implement execle without execve
+#endif
+// int execle(const char *path, const char *arg, ..., char * const envp[]);
+int execle(const char *path, const char *arg, ...) {
+  va_list args;
+  va_start(args, arg);
+  char const **argv = bear_strings_build(arg, &args);
+  char const **envp = va_arg(args, char const **);
+  va_end(args);
+
+  bear_report_call(__func__, (char const *const *)argv);
+  int const result =
+      call_execve(path, (char *const *)argv, (char *const *)envp);
+
+  bear_strings_release(argv);
+  return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+int posix_spawn(pid_t *restrict pid, const char *restrict path,
+                const posix_spawn_file_actions_t *file_actions,
+                const posix_spawnattr_t *restrict attrp,
+                char *const argv[restrict], char *const envp[restrict]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+int posix_spawnp(pid_t *restrict pid, const char *restrict file,
+                 const posix_spawn_file_actions_t *file_actions,
+                 const posix_spawnattr_t *restrict attrp,
+                 char *const argv[restrict], char *const envp[restrict]) {
+  bear_report_call(__func__, (char const *const *)argv);
+  return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
+}
+#endif
+
+/* These are the methods which forward the call to the standard implementation.
+ */
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+                       char *const envp[]) {
+  typedef int (*func)(const char *, char *const *, char *const *);
+
+  DLSYM(func, fp, "execve");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result = (*fp)(path, argv, (char *const *)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+                        char *const envp[]) {
+  typedef int (*func)(const char *, char *const *, char *const *);
+
+  DLSYM(func, fp, "execvpe");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result = (*fp)(file, argv, (char *const *)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]) {
+  typedef int (*func)(const char *file, char *const argv[]);
+
+  DLSYM(func, fp, "execvp");
+
+  bear_env_t current_env;
+  bear_capture_env_t(&current_env);
+  bear_reset_env_t(&initial_env);
+  int const result = (*fp)(file, argv);
+  bear_reset_env_t(&current_env);
+  bear_release_env_t(&current_env);
+
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+                       char *const argv[]) {
+  typedef int (*func)(const char *, const char *, char *const *);
+
+  DLSYM(func, fp, "execvP");
+
+  bear_env_t current_env;
+  bear_capture_env_t(&current_env);
+  bear_reset_env_t(&initial_env);
+  int const result = (*fp)(file, search_path, argv);
+  bear_reset_env_t(&current_env);
+  bear_release_env_t(&current_env);
+
+  return result;
+}
+#endif
+
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[],
+                      char *const envp[]) {
+  typedef int (*func)(const char *, char *const *, char *const *);
+
+  DLSYM(func, fp, "exect");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result = (*fp)(path, argv, (char *const *)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+                            const posix_spawn_file_actions_t *file_actions,
+                            const posix_spawnattr_t *restrict attrp,
+                            char *const argv[restrict],
+                            char *const envp[restrict]) {
+  typedef int (*func)(pid_t *restrict, const char *restrict,
+                      const posix_spawn_file_actions_t *,
+                      const posix_spawnattr_t *restrict, char *const *restrict,
+                      char *const *restrict);
+
+  DLSYM(func, fp, "posix_spawn");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result =
+      (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+                             const posix_spawn_file_actions_t *file_actions,
+                             const posix_spawnattr_t *restrict attrp,
+                             char *const argv[restrict],
+                             char *const envp[restrict]) {
+  typedef int (*func)(pid_t *restrict, const char *restrict,
+                      const posix_spawn_file_actions_t *,
+                      const posix_spawnattr_t *restrict, char *const *restrict,
+                      char *const *restrict);
+
+  DLSYM(func, fp, "posix_spawnp");
+
+  char const **const menvp = bear_update_environment(envp, &initial_env);
+  int const result =
+      (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
+  bear_strings_release(menvp);
+  return result;
+}
+#endif
+
+/* this method is to write log about the process creation. */
+
+static void bear_report_call(char const *fun, char const *const argv[]) {
+  static int const GS = 0x1d;
+  static int const RS = 0x1e;
+  static int const US = 0x1f;
+
+  if (!initialized)
+    return;
+
+  pthread_mutex_lock(&mutex);
+  const char *cwd = getcwd(NULL, 0);
+  if (0 == cwd) {
+    perror("bear: getcwd");
+    exit(EXIT_FAILURE);
+  }
+  char const *const out_dir = initial_env[0];
+  size_t const path_max_length = strlen(out_dir) + 32;
+  char filename[path_max_length];
+  if (-1 ==
+      snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
+    perror("bear: snprintf");
+    exit(EXIT_FAILURE);
+  }
+  FILE *fd = fopen(filename, "a+");
+  if (0 == fd) {
+    perror("bear: fopen");
+    exit(EXIT_FAILURE);
+  }
+  fprintf(fd, "%d%c", getpid(), RS);
+  fprintf(fd, "%d%c", getppid(), RS);
+  fprintf(fd, "%s%c", fun, RS);
+  fprintf(fd, "%s%c", cwd, RS);
+  size_t const argc = bear_strings_length(argv);
+  for (size_t it = 0; it < argc; ++it) {
+    fprintf(fd, "%s%c", argv[it], US);
+  }
+  fprintf(fd, "%c", GS);
+  if (fclose(fd)) {
+    perror("bear: fclose");
+    exit(EXIT_FAILURE);
+  }
+  free((void *)cwd);
+  pthread_mutex_unlock(&mutex);
+}
+
+/* update environment assure that chilren processes will copy the desired
+ * behaviour */
+
+static int bear_capture_env_t(bear_env_t *env) {
+  int status = 1;
+  for (size_t it = 0; it < ENV_SIZE; ++it) {
+    char const *const env_value = getenv(env_names[it]);
+    char const *const env_copy = (env_value) ? strdup(env_value) : env_value;
+    (*env)[it] = env_copy;
+    status &= (env_copy) ? 1 : 0;
+  }
+  return status;
+}
+
+static int bear_reset_env_t(bear_env_t *env) {
+  int status = 1;
+  for (size_t it = 0; it < ENV_SIZE; ++it) {
+    if ((*env)[it]) {
+      setenv(env_names[it], (*env)[it], 1);
+    } else {
+      unsetenv(env_names[it]);
+    }
+  }
+  return status;
+}
+
+static void bear_release_env_t(bear_env_t *env) {
+  for (size_t it = 0; it < ENV_SIZE; ++it) {
+    free((void *)(*env)[it]);
+    (*env)[it] = 0;
+  }
+}
+
+static char const **bear_update_environment(char *const envp[],
+                                            bear_env_t *env) {
+  char const **result = bear_strings_copy((char const **)envp);
+  for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
+    result = bear_update_environ(result, env_names[it], (*env)[it]);
+  return result;
+}
+
+static char const **bear_update_environ(char const *envs[], char const *key,
+                                        char const *const value) {
+  // find the key if it's there
+  size_t const key_length = strlen(key);
+  char const **it = envs;
+  for (; (it) && (*it); ++it) {
+    if ((0 == strncmp(*it, key, key_length)) && (strlen(*it) > key_length) &&
+        ('=' == (*it)[key_length]))
+      break;
+  }
+  // allocate a environment entry
+  size_t const value_length = strlen(value);
+  size_t const env_length = key_length + value_length + 2;
+  char *env = malloc(env_length);
+  if (0 == env) {
+    perror("bear: malloc [in env_update]");
+    exit(EXIT_FAILURE);
+  }
+  if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
+    perror("bear: snprintf");
+    exit(EXIT_FAILURE);
+  }
+  // replace or append the environment entry
+  if (it && *it) {
+    free((void *)*it);
+    *it = env;
+    return envs;
+  }
+  return bear_strings_append(envs, env);
+}
+
+static char **bear_get_environment() {
+#if defined HAVE_NSGETENVIRON
+  return *_NSGetEnviron();
+#else
+  return environ;
+#endif
+}
+
+/* util methods to deal with string arrays. environment and process arguments
+ * are both represented as string arrays. */
+
+static char const **bear_strings_build(char const *const arg, va_list *args) {
+  char const **result = 0;
+  size_t size = 0;
+  for (char const *it = arg; it; it = va_arg(*args, char const *)) {
+    result = realloc(result, (size + 1) * sizeof(char const *));
+    if (0 == result) {
+      perror("bear: realloc");
+      exit(EXIT_FAILURE);
+    }
+    char const *copy = strdup(it);
+    if (0 == copy) {
+      perror("bear: strdup");
+      exit(EXIT_FAILURE);
+    }
+    result[size++] = copy;
+  }
+  result = realloc(result, (size + 1) * sizeof(char const *));
+  if (0 == result) {
+    perror("bear: realloc");
+    exit(EXIT_FAILURE);
+  }
+  result[size++] = 0;
+
+  return result;
+}
+
+static char const **bear_strings_copy(char const **const in) {
+  size_t const size = bear_strings_length(in);
+
+  char const **const result = malloc((size + 1) * sizeof(char const *));
+  if (0 == result) {
+    perror("bear: malloc");
+    exit(EXIT_FAILURE);
+  }
+
+  char const **out_it = result;
+  for (char const *const *in_it = in; (in_it) && (*in_it); ++in_it, ++out_it) {
+    *out_it = strdup(*in_it);
+    if (0 == *out_it) {
+      perror("bear: strdup");
+      exit(EXIT_FAILURE);
+    }
+  }
+  *out_it = 0;
+  return result;
+}
+
+static char const **bear_strings_append(char const **const in,
+                                        char const *const e) {
+  size_t size = bear_strings_length(in);
+  char const **result = realloc(in, (size + 2) * sizeof(char const *));
+  if (0 == result) {
+    perror("bear: realloc");
+    exit(EXIT_FAILURE);
+  }
+  result[size++] = e;
+  result[size++] = 0;
+  return result;
+}
+
+static size_t bear_strings_length(char const *const *const in) {
+  size_t result = 0;
+  for (char const *const *it = in; (it) && (*it); ++it)
+    ++result;
+  return result;
+}
+
+static void bear_strings_release(char const **in) {
+  for (char const *const *it = in; (it) && (*it); ++it) {
+    free((void *)*it);
+  }
+  free((void *)in);
+}
\ No newline at end of file

diff  --git a/clang/tools/scan-build-py/libscanbuild/__init__.py b/clang/tools/scan-build-py/lib/libscanbuild/__init__.py
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/__init__.py
rename to clang/tools/scan-build-py/lib/libscanbuild/__init__.py

diff  --git a/clang/tools/scan-build-py/libscanbuild/analyze.py b/clang/tools/scan-build-py/lib/libscanbuild/analyze.py
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/analyze.py
rename to clang/tools/scan-build-py/lib/libscanbuild/analyze.py

diff  --git a/clang/tools/scan-build-py/libscanbuild/arguments.py b/clang/tools/scan-build-py/lib/libscanbuild/arguments.py
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/arguments.py
rename to clang/tools/scan-build-py/lib/libscanbuild/arguments.py

diff  --git a/clang/tools/scan-build-py/libscanbuild/clang.py b/clang/tools/scan-build-py/lib/libscanbuild/clang.py
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/clang.py
rename to clang/tools/scan-build-py/lib/libscanbuild/clang.py

diff  --git a/clang/tools/scan-build-py/libscanbuild/compilation.py b/clang/tools/scan-build-py/lib/libscanbuild/compilation.py
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/compilation.py
rename to clang/tools/scan-build-py/lib/libscanbuild/compilation.py

diff  --git a/clang/tools/scan-build-py/libscanbuild/intercept.py b/clang/tools/scan-build-py/lib/libscanbuild/intercept.py
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/intercept.py
rename to clang/tools/scan-build-py/lib/libscanbuild/intercept.py

diff  --git a/clang/tools/scan-build-py/libscanbuild/report.py b/clang/tools/scan-build-py/lib/libscanbuild/report.py
similarity index 97%
rename from clang/tools/scan-build-py/libscanbuild/report.py
rename to clang/tools/scan-build-py/lib/libscanbuild/report.py
index 46338b86d26d6..729b25e6350f3 100644
--- a/clang/tools/scan-build-py/libscanbuild/report.py
+++ b/clang/tools/scan-build-py/lib/libscanbuild/report.py
@@ -379,21 +379,22 @@ def match_and_update_run(message, runs_count_offset):
 def parse_bug_plist(filename):
     """ Returns the generator of bugs from a single .plist file. """
 
-    content = plistlib.readPlist(filename)
-    files = content.get('files')
-    for bug in content.get('diagnostics', []):
-        if len(files) <= int(bug['location']['file']):
-            logging.warning('Parsing bug from "%s" failed', filename)
-            continue
-
-        yield {
-            'result': filename,
-            'bug_type': bug['type'],
-            'bug_category': bug['category'],
-            'bug_line': int(bug['location']['line']),
-            'bug_path_length': int(bug['location']['col']),
-            'bug_file': files[int(bug['location']['file'])]
-        }
+    with open(filename, 'rb') as fp:
+      content = plistlib.load(fp)
+      files = content.get('files')
+      for bug in content.get('diagnostics', []):
+          if len(files) <= int(bug['location']['file']):
+              logging.warning('Parsing bug from "%s" failed', filename)
+              continue
+
+          yield {
+              'result': filename,
+              'bug_type': bug['type'],
+              'bug_category': bug['category'],
+              'bug_line': int(bug['location']['line']),
+              'bug_path_length': int(bug['location']['col']),
+              'bug_file': files[int(bug['location']['file'])]
+          }
 
 
 def parse_bug_html(filename):

diff  --git a/clang/tools/scan-build-py/libscanbuild/resources/scanview.css b/clang/tools/scan-build-py/lib/libscanbuild/resources/scanview.css
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/resources/scanview.css
rename to clang/tools/scan-build-py/lib/libscanbuild/resources/scanview.css

diff  --git a/clang/tools/scan-build-py/libscanbuild/resources/selectable.js b/clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
similarity index 60%
rename from clang/tools/scan-build-py/libscanbuild/resources/selectable.js
rename to clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
index 53f6a8da13d8c..c88ee78568ef7 100644
--- a/clang/tools/scan-build-py/libscanbuild/resources/selectable.js
+++ b/clang/tools/scan-build-py/lib/libscanbuild/resources/selectable.js
@@ -1,7 +1,6 @@
-function SetDisplay(RowClass, DisplayVal)
-{
+function SetDisplay(RowClass, DisplayVal) {
   var Rows = document.getElementsByTagName("tr");
-  for ( var i = 0 ; i < Rows.length; ++i ) {
+  for (var i = 0; i < Rows.length; ++i) {
     if (Rows[i].className == RowClass) {
       Rows[i].style.display = DisplayVal;
     }
@@ -10,24 +9,24 @@ function SetDisplay(RowClass, DisplayVal)
 
 function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
   var Inputs = document.getElementsByTagName("input");
-  for ( var i = 0 ; i < Inputs.length; ++i ) {
+  for (var i = 0; i < Inputs.length; ++i) {
     if (Inputs[i].type == "checkbox") {
-      if(Inputs[i] != SummaryCheckButton) {
+      if (Inputs[i] != SummaryCheckButton) {
         Inputs[i].checked = SummaryCheckButton.checked;
         Inputs[i].onclick();
-	  }
+      }
     }
   }
 }
 
-function returnObjById( id ) {
-    if (document.getElementById)
-        var returnVar = document.getElementById(id);
-    else if (document.all)
-        var returnVar = document.all[id];
-    else if (document.layers)
-        var returnVar = document.layers[id];
-    return returnVar;
+function returnObjById(id) {
+  if (document.getElementById)
+    var returnVar = document.getElementById(id);
+  else if (document.all)
+    var returnVar = document.all[id];
+  else if (document.layers)
+    var returnVar = document.layers[id];
+  return returnVar;
 }
 
 var NumUnchecked = 0;
@@ -38,8 +37,7 @@ function ToggleDisplay(CheckButton, ClassName) {
     if (--NumUnchecked == 0) {
       returnObjById("AllBugsCheck").checked = true;
     }
-  }
-  else {
+  } else {
     SetDisplay(ClassName, "none");
     NumUnchecked++;
     returnObjById("AllBugsCheck").checked = false;

diff  --git a/clang/tools/scan-build-py/lib/libscanbuild/resources/sorttable.js b/clang/tools/scan-build-py/lib/libscanbuild/resources/sorttable.js
new file mode 100644
index 0000000000000..b98f012e34d65
--- /dev/null
+++ b/clang/tools/scan-build-py/lib/libscanbuild/resources/sorttable.js
@@ -0,0 +1,535 @@
+/*
+  SortTable
+  version 2
+  7th April 2007
+  Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+  Instructions:
+  Download this file
+  Add <script src="sorttable.js"></script> to your HTML
+  Add class="sortable" to any table you'd like to make sortable
+  Click on the headers to sort
+
+  Thanks to many, many people for contributions and suggestions.
+  Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+  This basically means: do what you want with it.
+*/
+
+var stIsIE = /*@cc_on!@*/ false;
+
+sorttable = {
+  init : function() {
+    // quit if this function has already been called
+    if (arguments.callee.done)
+      return;
+    // flag this function so we don't do the same thing twice
+    arguments.callee.done = true;
+    // kill the timer
+    if (_timer)
+      clearInterval(_timer);
+
+    if (!document.createElement || !document.getElementsByTagName)
+      return;
+
+    sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+    forEach(document.getElementsByTagName('table'), function(table) {
+      if (table.className.search(/\bsortable\b/) != -1) {
+        sorttable.makeSortable(table);
+      }
+    });
+  },
+
+  makeSortable : function(table) {
+    if (table.getElementsByTagName('thead').length == 0) {
+      // table doesn't have a tHead. Since it should have, create one and
+      // put the first table row in it.
+      the = document.createElement('thead');
+      the.appendChild(table.rows[0]);
+      table.insertBefore(the, table.firstChild);
+    }
+    // Safari doesn't support table.tHead, sigh
+    if (table.tHead == null)
+      table.tHead = table.getElementsByTagName('thead')[0];
+
+    if (table.tHead.rows.length != 1)
+      return; // can't cope with two header rows
+
+    // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+    // "total" rows, for example). This is B&R, since what you're supposed
+    // to do is put them in a tfoot. So, if there are sortbottom rows,
+    // for backward compatibility, move them to tfoot (creating it if needed).
+    sortbottomrows = [];
+    for (var i = 0; i < table.rows.length; i++) {
+      if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+        sortbottomrows[sortbottomrows.length] = table.rows[i];
+      }
+    }
+    if (sortbottomrows) {
+      if (table.tFoot == null) {
+        // table doesn't have a tfoot. Create one.
+        tfo = document.createElement('tfoot');
+        table.appendChild(tfo);
+      }
+      for (var i = 0; i < sortbottomrows.length; i++) {
+        tfo.appendChild(sortbottomrows[i]);
+      }
+      delete sortbottomrows;
+    }
+
+    // work through each column and calculate its type
+    headrow = table.tHead.rows[0].cells;
+    for (var i = 0; i < headrow.length; i++) {
+      // manually override the type with a sorttable_type attribute
+      if (!headrow[i].className.match(
+              /\bsorttable_nosort\b/)) { // skip this col
+        mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+        if (mtch) {
+          override = mtch[1];
+        }
+        if (mtch && typeof sorttable["sort_" + override] == 'function') {
+          headrow[i].sorttable_sortfunction = sorttable["sort_" + override];
+        } else {
+          headrow[i].sorttable_sortfunction = sorttable.guessType(table, i);
+        }
+        // make it clickable to sort
+        headrow[i].sorttable_columnindex = i;
+        headrow[i].sorttable_tbody = table.tBodies[0];
+        dean_addEvent(headrow[i], "click", function(e) {
+          if (this.className.search(/\bsorttable_sorted\b/) != -1) {
+            // if we're already sorted by this column, just
+            // reverse the table, which is quicker
+            sorttable.reverse(this.sorttable_tbody);
+            this.className = this.className.replace('sorttable_sorted',
+                                                    'sorttable_sorted_reverse');
+            this.removeChild(document.getElementById('sorttable_sortfwdind'));
+            sortrevind = document.createElement('span');
+            sortrevind.id = "sorttable_sortrevind";
+            sortrevind.innerHTML = stIsIE
+                                       ? '&nbsp<font face="webdings">5</font>'
+                                       : ' &#x25B4;';
+            this.appendChild(sortrevind);
+            return;
+          }
+          if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+            // if we're already sorted by this column in reverse, just
+            // re-reverse the table, which is quicker
+            sorttable.reverse(this.sorttable_tbody);
+            this.className = this.className.replace('sorttable_sorted_reverse',
+                                                    'sorttable_sorted');
+            this.removeChild(document.getElementById('sorttable_sortrevind'));
+            sortfwdind = document.createElement('span');
+            sortfwdind.id = "sorttable_sortfwdind";
+            sortfwdind.innerHTML = stIsIE
+                                       ? '&nbsp<font face="webdings">6</font>'
+                                       : ' &#x25BE;';
+            this.appendChild(sortfwdind);
+            return;
+          }
+
+          // remove sorttable_sorted classes
+          theadrow = this.parentNode;
+          forEach(theadrow.childNodes, function(cell) {
+            if (cell.nodeType == 1) { // an element
+              cell.className =
+                  cell.className.replace('sorttable_sorted_reverse', '');
+              cell.className = cell.className.replace('sorttable_sorted', '');
+            }
+          });
+          sortfwdind = document.getElementById('sorttable_sortfwdind');
+          if (sortfwdind) {
+            sortfwdind.parentNode.removeChild(sortfwdind);
+          }
+          sortrevind = document.getElementById('sorttable_sortrevind');
+          if (sortrevind) {
+            sortrevind.parentNode.removeChild(sortrevind);
+          }
+
+          this.className += ' sorttable_sorted';
+          sortfwdind = document.createElement('span');
+          sortfwdind.id = "sorttable_sortfwdind";
+          sortfwdind.innerHTML =
+              stIsIE ? '&nbsp<font face="webdings">6</font>' : ' &#x25BE;';
+          this.appendChild(sortfwdind);
+
+          // build an array to sort. This is a Schwartzian transform thing,
+          // i.e., we "decorate" each row with the actual sort key,
+          // sort based on the sort keys, and then put the rows back in order
+          // which is a lot faster because you only do getInnerText once per row
+          row_array = [];
+          col = this.sorttable_columnindex;
+          rows = this.sorttable_tbody.rows;
+          for (var j = 0; j < rows.length; j++) {
+            row_array[row_array.length] =
+                [ sorttable.getInnerText(rows[j].cells[col]), rows[j] ];
+          }
+          /* If you want a stable sort, uncomment the following line */
+          sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
+          /* and comment out this one */
+          // row_array.sort(this.sorttable_sortfunction);
+
+          tb = this.sorttable_tbody;
+          for (var j = 0; j < row_array.length; j++) {
+            tb.appendChild(row_array[j][1]);
+          }
+
+          delete row_array;
+        });
+      }
+    }
+  },
+
+  guessType : function(table, column) {
+    // guess the type of a column based on its first non-blank row
+    sortfn = sorttable.sort_alpha;
+    for (var i = 0; i < table.tBodies[0].rows.length; i++) {
+      text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
+      if (text != '') {
+        if (text.match(/^-?[」$、]?[\d,.]+%?$/)) {
+          return sorttable.sort_numeric;
+        }
+        // check for a date: dd/mm/yyyy or dd/mm/yy
+        // can have / or . or - as separator
+        // can be mm/dd as well
+        possdate = text.match(sorttable.DATE_RE)
+        if (possdate) {
+          // looks like a date
+          first = parseInt(possdate[1]);
+          second = parseInt(possdate[2]);
+          if (first > 12) {
+            // definitely dd/mm
+            return sorttable.sort_ddmm;
+          } else if (second > 12) {
+            return sorttable.sort_mmdd;
+          } else {
+            // looks like a date, but we can't tell which, so assume
+            // that it's dd/mm (English imperialism!) and keep looking
+            sortfn = sorttable.sort_ddmm;
+          }
+        }
+      }
+    }
+    return sortfn;
+  },
+
+  getInnerText : function(node) {
+    // gets the text we want to use for sorting for a cell.
+    // strips leading and trailing whitespace.
+    // this is *not* a generic getInnerText function; it's special to sorttable.
+    // for example, you can override the cell text with a customkey attribute.
+    // it also gets .value for <input> fields.
+
+    hasInputs = (typeof node.getElementsByTagName == 'function') &&
+                node.getElementsByTagName('input').length;
+
+    if (node.getAttribute("sorttable_customkey") != null) {
+      return node.getAttribute("sorttable_customkey");
+    } else if (typeof node.textContent != 'undefined' && !hasInputs) {
+      return node.textContent.replace(/^\s+|\s+$/g, '');
+    } else if (typeof node.innerText != 'undefined' && !hasInputs) {
+      return node.innerText.replace(/^\s+|\s+$/g, '');
+    } else if (typeof node.text != 'undefined' && !hasInputs) {
+      return node.text.replace(/^\s+|\s+$/g, '');
+    } else {
+      switch (node.nodeType) {
+      case 3:
+        if (node.nodeName.toLowerCase() == 'input') {
+          return node.value.replace(/^\s+|\s+$/g, '');
+        }
+      case 4:
+        return node.nodeValue.replace(/^\s+|\s+$/g, '');
+        break;
+      case 1:
+      case 11:
+        var innerText = '';
+        for (var i = 0; i < node.childNodes.length; i++) {
+          innerText += sorttable.getInnerText(node.childNodes[i]);
+        }
+        return innerText.replace(/^\s+|\s+$/g, '');
+        break;
+      default:
+        return '';
+      }
+    }
+  },
+
+  reverse : function(tbody) {
+    // reverse the rows in a tbody
+    newrows = [];
+    for (var i = 0; i < tbody.rows.length; i++) {
+      newrows[newrows.length] = tbody.rows[i];
+    }
+    for (var i = newrows.length - 1; i >= 0; i--) {
+      tbody.appendChild(newrows[i]);
+    }
+    delete newrows;
+  },
+
+  /* sort functions
+     each sort function takes two parameters, a and b
+     you are comparing a[0] and b[0] */
+  sort_numeric : function(a, b) {
+    aa = parseFloat(a[0].replace(/[^0-9.-]/g, ''));
+    if (isNaN(aa))
+      aa = 0;
+    bb = parseFloat(b[0].replace(/[^0-9.-]/g, ''));
+    if (isNaN(bb))
+      bb = 0;
+    return aa - bb;
+  },
+  sort_alpha : function(a, b) {
+    if (a[0] == b[0])
+      return 0;
+    if (a[0] < b[0])
+      return -1;
+    return 1;
+  },
+  sort_ddmm : function(a, b) {
+    mtch = a[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    m = mtch[2];
+    d = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt1 = y + m + d;
+    mtch = b[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    m = mtch[2];
+    d = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt2 = y + m + d;
+    if (dt1 == dt2)
+      return 0;
+    if (dt1 < dt2)
+      return -1;
+    return 1;
+  },
+  sort_mmdd : function(a, b) {
+    mtch = a[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    d = mtch[2];
+    m = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt1 = y + m + d;
+    mtch = b[0].match(sorttable.DATE_RE);
+    y = mtch[3];
+    d = mtch[2];
+    m = mtch[1];
+    if (m.length == 1)
+      m = '0' + m;
+    if (d.length == 1)
+      d = '0' + d;
+    dt2 = y + m + d;
+    if (dt1 == dt2)
+      return 0;
+    if (dt1 < dt2)
+      return -1;
+    return 1;
+  },
+
+  shaker_sort : function(list, comp_func) {
+    // A stable sort function to allow multi-level sorting of data
+    // see: http://en.wikipedia.org/wiki/Cocktail_sort
+    // thanks to Joseph Nahmias
+    var b = 0;
+    var t = list.length - 1;
+    var swap = true;
+
+    while (swap) {
+      swap = false;
+      for (var i = b; i < t; ++i) {
+        if (comp_func(list[i], list[i + 1]) > 0) {
+          var q = list[i];
+          list[i] = list[i + 1];
+          list[i + 1] = q;
+          swap = true;
+        }
+      } // for
+      t--;
+
+      if (!swap)
+        break;
+
+      for (var i = t; i > b; --i) {
+        if (comp_func(list[i], list[i - 1]) < 0) {
+          var q = list[i];
+          list[i] = list[i - 1];
+          list[i - 1] = q;
+          swap = true;
+        }
+      } // for
+      b++;
+
+    } // while(swap)
+  }
+}
+
+/* ******************************************************************
+   Supporting functions: bundled here to avoid depending on a library
+   ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+  document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+    document.write("<script id=__ie_onload defer
+src=javascript:void(0)><\/script>"); var script =
+document.getElementById("__ie_onload"); script.onreadystatechange = function() {
+        if (this.readyState == "complete") {
+            sorttable.init(); // call the onload handler
+        }
+    };
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+  var _timer = setInterval(function() {
+    if (/loaded|complete/.test(document.readyState)) {
+      sorttable.init(); // call the onload handler
+    }
+  }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+  if (element.addEventListener) {
+    element.addEventListener(type, handler, false);
+  } else {
+    // assign each event handler a unique ID
+    if (!handler.$$guid)
+      handler.$$guid = dean_addEvent.guid++;
+    // create a hash table of event types for the element
+    if (!element.events)
+      element.events = {};
+    // create a hash table of event handlers for each element/event pair
+    var handlers = element.events[type];
+    if (!handlers) {
+      handlers = element.events[type] = {};
+      // store the existing event handler (if there is one)
+      if (element["on" + type]) {
+        handlers[0] = element["on" + type];
+      }
+    }
+    // store the event handler in the hash table
+    handlers[handler.$$guid] = handler;
+    // assign a global event handler to do all the work
+    element["on" + type] = handleEvent;
+  }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+  if (element.removeEventListener) {
+    element.removeEventListener(type, handler, false);
+  } else {
+    // delete the event handler from the hash table
+    if (element.events && element.events[type]) {
+      delete element.events[type][handler.$$guid];
+    }
+  }
+};
+
+function handleEvent(event) {
+  var returnValue = true;
+  // grab the event object (IE uses a global event object)
+  event =
+      event ||
+      fixEvent(
+          ((this.ownerDocument || this.document || this).parentWindow || window)
+              .event);
+  // get a reference to the hash table of event handlers
+  var handlers = this.events[event.type];
+  // execute each event handler
+  for (var i in handlers) {
+    this.$$handleEvent = handlers[i];
+    if (this.$$handleEvent(event) === false) {
+      returnValue = false;
+    }
+  }
+  return returnValue;
+};
+
+function fixEvent(event) {
+  // add W3C standard event methods
+  event.preventDefault = fixEvent.preventDefault;
+  event.stopPropagation = fixEvent.stopPropagation;
+  return event;
+};
+fixEvent.preventDefault = function() { this.returnValue = false; };
+fixEvent.stopPropagation = function() { this.cancelBubble = true; }
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+        forEach, version 1.0
+        Copyright 2006, Dean Edwards
+        License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+  Array.forEach = function(array, block, context) {
+    for (var i = 0; i < array.length; i++) {
+      block.call(context, array[i], i, array);
+    }
+  };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+  for (var key in object) {
+    if (typeof this.prototype[key] == "undefined") {
+      block.call(context, object[key], key, object);
+    }
+  }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+  Array.forEach(
+      string.split(""),
+      function(chr, index) { block.call(context, chr, index, string); });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+  if (object) {
+    var resolve = Object; // default
+    if (object instanceof Function) {
+      // functions have a "length" property
+      resolve = Function;
+    } else if (object.forEach instanceof Function) {
+      // the object implements a custom forEach method so use that
+      object.forEach(block, context);
+      return;
+    } else if (typeof object == "string") {
+      // the object is a string
+      resolve = String;
+    } else if (typeof object.length == "number") {
+      // the object is array-like
+      resolve = Array;
+    }
+    resolve.forEach(object, block, context);
+  }
+};
\ No newline at end of file

diff  --git a/clang/tools/scan-build-py/libscanbuild/shell.py b/clang/tools/scan-build-py/lib/libscanbuild/shell.py
similarity index 100%
rename from clang/tools/scan-build-py/libscanbuild/shell.py
rename to clang/tools/scan-build-py/lib/libscanbuild/shell.py

diff  --git a/clang/tools/scan-build-py/libear/ear.c b/clang/tools/scan-build-py/libear/ear.c
deleted file mode 100644
index 21c57684745e6..0000000000000
--- a/clang/tools/scan-build-py/libear/ear.c
+++ /dev/null
@@ -1,604 +0,0 @@
-/* -*- coding: utf-8 -*-
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-*/
-
-/**
- * This file implements a shared library. This library can be pre-loaded by
- * the dynamic linker of the Operating System (OS). It implements a few function
- * related to process creation. By pre-load this library the executed process
- * uses these functions instead of those from the standard library.
- *
- * The idea here is to inject a logic before call the real methods. The logic is
- * to dump the call into a file. To call the real method this library is doing
- * the job of the dynamic linker.
- *
- * The only input for the log writing is about the destination directory.
- * This is passed as environment variable.
- */
-
-#include "config.h"
-
-#include <stddef.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <dlfcn.h>
-#include <pthread.h>
-
-#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
-#include <spawn.h>
-#endif
-
-#if defined HAVE_NSGETENVIRON
-# include <crt_externs.h>
-#else
-extern char **environ;
-#endif
-
-#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
-#ifdef APPLE
-# define ENV_FLAT    "DYLD_FORCE_FLAT_NAMESPACE"
-# define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
-# define ENV_SIZE 3
-#else
-# define ENV_PRELOAD "LD_PRELOAD"
-# define ENV_SIZE 2
-#endif
-
-#define DLSYM(TYPE_, VAR_, SYMBOL_)                                            \
-    union {                                                                    \
-        void *from;                                                            \
-        TYPE_ to;                                                              \
-    } cast;                                                                    \
-    if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) {                        \
-        perror("bear: dlsym");                                                 \
-        exit(EXIT_FAILURE);                                                    \
-    }                                                                          \
-    TYPE_ const VAR_ = cast.to;
-
-
-typedef char const * bear_env_t[ENV_SIZE];
-
-static int bear_capture_env_t(bear_env_t *env);
-static int bear_reset_env_t(bear_env_t *env);
-static void bear_release_env_t(bear_env_t *env);
-static char const **bear_update_environment(char *const envp[], bear_env_t *env);
-static char const **bear_update_environ(char const **in, char const *key, char const *value);
-static char **bear_get_environment();
-static void bear_report_call(char const *fun, char const *const argv[]);
-static char const **bear_strings_build(char const *arg, va_list *ap);
-static char const **bear_strings_copy(char const **const in);
-static char const **bear_strings_append(char const **in, char const *e);
-static size_t bear_strings_length(char const *const *in);
-static void bear_strings_release(char const **);
-
-
-static bear_env_t env_names =
-    { ENV_OUTPUT
-    , ENV_PRELOAD
-#ifdef ENV_FLAT
-    , ENV_FLAT
-#endif
-    };
-
-static bear_env_t initial_env =
-    { 0
-    , 0
-#ifdef ENV_FLAT
-    , 0
-#endif
-    };
-
-static int initialized = 0;
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void on_load(void) __attribute__((constructor));
-static void on_unload(void) __attribute__((destructor));
-
-
-#ifdef HAVE_EXECVE
-static int call_execve(const char *path, char *const argv[],
-                       char *const envp[]);
-#endif
-#ifdef HAVE_EXECVP
-static int call_execvp(const char *file, char *const argv[]);
-#endif
-#ifdef HAVE_EXECVPE
-static int call_execvpe(const char *file, char *const argv[],
-                        char *const envp[]);
-#endif
-#ifdef HAVE_EXECVP2
-static int call_execvP(const char *file, const char *search_path,
-                       char *const argv[]);
-#endif
-#ifdef HAVE_EXECT
-static int call_exect(const char *path, char *const argv[],
-                      char *const envp[]);
-#endif
-#ifdef HAVE_POSIX_SPAWN
-static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
-                            const posix_spawn_file_actions_t *file_actions,
-                            const posix_spawnattr_t *restrict attrp,
-                            char *const argv[restrict],
-                            char *const envp[restrict]);
-#endif
-#ifdef HAVE_POSIX_SPAWNP
-static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
-                             const posix_spawn_file_actions_t *file_actions,
-                             const posix_spawnattr_t *restrict attrp,
-                             char *const argv[restrict],
-                             char *const envp[restrict]);
-#endif
-
-
-/* Initialization method to Captures the relevant environment variables.
- */
-
-static void on_load(void) {
-    pthread_mutex_lock(&mutex);
-    if (!initialized)
-        initialized = bear_capture_env_t(&initial_env);
-    pthread_mutex_unlock(&mutex);
-}
-
-static void on_unload(void) {
-    pthread_mutex_lock(&mutex);
-    bear_release_env_t(&initial_env);
-    initialized = 0;
-    pthread_mutex_unlock(&mutex);
-}
-
-
-/* These are the methods we are try to hijack.
- */
-
-#ifdef HAVE_EXECVE
-int execve(const char *path, char *const argv[], char *const envp[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execve(path, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECV
-#ifndef HAVE_EXECVE
-#error can not implement execv without execve
-#endif
-int execv(const char *path, char *const argv[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    char * const * envp = bear_get_environment();
-    return call_execve(path, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECVPE
-int execvpe(const char *file, char *const argv[], char *const envp[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execvpe(file, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECVP
-int execvp(const char *file, char *const argv[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execvp(file, argv);
-}
-#endif
-
-#ifdef HAVE_EXECVP2
-int execvP(const char *file, const char *search_path, char *const argv[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_execvP(file, search_path, argv);
-}
-#endif
-
-#ifdef HAVE_EXECT
-int exect(const char *path, char *const argv[], char *const envp[]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_exect(path, argv, envp);
-}
-#endif
-
-#ifdef HAVE_EXECL
-# ifndef HAVE_EXECVE
-#  error can not implement execl without execve
-# endif
-int execl(const char *path, const char *arg, ...) {
-    va_list args;
-    va_start(args, arg);
-    char const **argv = bear_strings_build(arg, &args);
-    va_end(args);
-
-    bear_report_call(__func__, (char const *const *)argv);
-    char * const * envp = bear_get_environment();
-    int const result = call_execve(path, (char *const *)argv, envp);
-
-    bear_strings_release(argv);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECLP
-# ifndef HAVE_EXECVP
-#  error can not implement execlp without execvp
-# endif
-int execlp(const char *file, const char *arg, ...) {
-    va_list args;
-    va_start(args, arg);
-    char const **argv = bear_strings_build(arg, &args);
-    va_end(args);
-
-    bear_report_call(__func__, (char const *const *)argv);
-    int const result = call_execvp(file, (char *const *)argv);
-
-    bear_strings_release(argv);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECLE
-# ifndef HAVE_EXECVE
-#  error can not implement execle without execve
-# endif
-// int execle(const char *path, const char *arg, ..., char * const envp[]);
-int execle(const char *path, const char *arg, ...) {
-    va_list args;
-    va_start(args, arg);
-    char const **argv = bear_strings_build(arg, &args);
-    char const **envp = va_arg(args, char const **);
-    va_end(args);
-
-    bear_report_call(__func__, (char const *const *)argv);
-    int const result =
-        call_execve(path, (char *const *)argv, (char *const *)envp);
-
-    bear_strings_release(argv);
-    return result;
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWN
-int posix_spawn(pid_t *restrict pid, const char *restrict path,
-                const posix_spawn_file_actions_t *file_actions,
-                const posix_spawnattr_t *restrict attrp,
-                char *const argv[restrict], char *const envp[restrict]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWNP
-int posix_spawnp(pid_t *restrict pid, const char *restrict file,
-                 const posix_spawn_file_actions_t *file_actions,
-                 const posix_spawnattr_t *restrict attrp,
-                 char *const argv[restrict], char *const envp[restrict]) {
-    bear_report_call(__func__, (char const *const *)argv);
-    return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
-}
-#endif
-
-/* These are the methods which forward the call to the standard implementation.
- */
-
-#ifdef HAVE_EXECVE
-static int call_execve(const char *path, char *const argv[],
-                       char *const envp[]) {
-    typedef int (*func)(const char *, char *const *, char *const *);
-
-    DLSYM(func, fp, "execve");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result = (*fp)(path, argv, (char *const *)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECVPE
-static int call_execvpe(const char *file, char *const argv[],
-                        char *const envp[]) {
-    typedef int (*func)(const char *, char *const *, char *const *);
-
-    DLSYM(func, fp, "execvpe");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result = (*fp)(file, argv, (char *const *)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECVP
-static int call_execvp(const char *file, char *const argv[]) {
-    typedef int (*func)(const char *file, char *const argv[]);
-
-    DLSYM(func, fp, "execvp");
-
-    bear_env_t current_env;
-    bear_capture_env_t(&current_env);
-    bear_reset_env_t(&initial_env);
-    int const result = (*fp)(file, argv);
-    bear_reset_env_t(&current_env);
-    bear_release_env_t(&current_env);
-
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECVP2
-static int call_execvP(const char *file, const char *search_path,
-                       char *const argv[]) {
-    typedef int (*func)(const char *, const char *, char *const *);
-
-    DLSYM(func, fp, "execvP");
-
-    bear_env_t current_env;
-    bear_capture_env_t(&current_env);
-    bear_reset_env_t(&initial_env);
-    int const result = (*fp)(file, search_path, argv);
-    bear_reset_env_t(&current_env);
-    bear_release_env_t(&current_env);
-
-    return result;
-}
-#endif
-
-#ifdef HAVE_EXECT
-static int call_exect(const char *path, char *const argv[],
-                      char *const envp[]) {
-    typedef int (*func)(const char *, char *const *, char *const *);
-
-    DLSYM(func, fp, "exect");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result = (*fp)(path, argv, (char *const *)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWN
-static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
-                            const posix_spawn_file_actions_t *file_actions,
-                            const posix_spawnattr_t *restrict attrp,
-                            char *const argv[restrict],
-                            char *const envp[restrict]) {
-    typedef int (*func)(pid_t *restrict, const char *restrict,
-                        const posix_spawn_file_actions_t *,
-                        const posix_spawnattr_t *restrict,
-                        char *const *restrict, char *const *restrict);
-
-    DLSYM(func, fp, "posix_spawn");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result =
-        (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-#ifdef HAVE_POSIX_SPAWNP
-static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
-                             const posix_spawn_file_actions_t *file_actions,
-                             const posix_spawnattr_t *restrict attrp,
-                             char *const argv[restrict],
-                             char *const envp[restrict]) {
-    typedef int (*func)(pid_t *restrict, const char *restrict,
-                        const posix_spawn_file_actions_t *,
-                        const posix_spawnattr_t *restrict,
-                        char *const *restrict, char *const *restrict);
-
-    DLSYM(func, fp, "posix_spawnp");
-
-    char const **const menvp = bear_update_environment(envp, &initial_env);
-    int const result =
-        (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
-    bear_strings_release(menvp);
-    return result;
-}
-#endif
-
-/* this method is to write log about the process creation. */
-
-static void bear_report_call(char const *fun, char const *const argv[]) {
-    static int const GS = 0x1d;
-    static int const RS = 0x1e;
-    static int const US = 0x1f;
-
-    if (!initialized)
-        return;
-
-    pthread_mutex_lock(&mutex);
-    const char *cwd = getcwd(NULL, 0);
-    if (0 == cwd) {
-        perror("bear: getcwd");
-        exit(EXIT_FAILURE);
-    }
-    char const * const out_dir = initial_env[0];
-    size_t const path_max_length = strlen(out_dir) + 32;
-    char filename[path_max_length];
-    if (-1 == snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
-        perror("bear: snprintf");
-        exit(EXIT_FAILURE);
-    }
-    FILE * fd = fopen(filename, "a+");
-    if (0 == fd) {
-        perror("bear: fopen");
-        exit(EXIT_FAILURE);
-    }
-    fprintf(fd, "%d%c", getpid(), RS);
-    fprintf(fd, "%d%c", getppid(), RS);
-    fprintf(fd, "%s%c", fun, RS);
-    fprintf(fd, "%s%c", cwd, RS);
-    size_t const argc = bear_strings_length(argv);
-    for (size_t it = 0; it < argc; ++it) {
-        fprintf(fd, "%s%c", argv[it], US);
-    }
-    fprintf(fd, "%c", GS);
-    if (fclose(fd)) {
-        perror("bear: fclose");
-        exit(EXIT_FAILURE);
-    }
-    free((void *)cwd);
-    pthread_mutex_unlock(&mutex);
-}
-
-/* update environment assure that chilren processes will copy the desired
- * behaviour */
-
-static int bear_capture_env_t(bear_env_t *env) {
-    int status = 1;
-    for (size_t it = 0; it < ENV_SIZE; ++it) {
-        char const * const env_value = getenv(env_names[it]);
-        char const * const env_copy = (env_value) ? strdup(env_value) : env_value;
-        (*env)[it] = env_copy;
-        status &= (env_copy) ? 1 : 0;
-    }
-    return status;
-}
-
-static int bear_reset_env_t(bear_env_t *env) {
-    int status = 1;
-    for (size_t it = 0; it < ENV_SIZE; ++it) {
-        if ((*env)[it]) {
-            setenv(env_names[it], (*env)[it], 1);
-        } else {
-            unsetenv(env_names[it]);
-        }
-    }
-    return status;
-}
-
-static void bear_release_env_t(bear_env_t *env) {
-    for (size_t it = 0; it < ENV_SIZE; ++it) {
-        free((void *)(*env)[it]);
-        (*env)[it] = 0;
-    }
-}
-
-static char const **bear_update_environment(char *const envp[], bear_env_t *env) {
-    char const **result = bear_strings_copy((char const **)envp);
-    for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
-        result = bear_update_environ(result, env_names[it], (*env)[it]);
-    return result;
-}
-
-static char const **bear_update_environ(char const *envs[], char const *key, char const * const value) {
-    // find the key if it's there
-    size_t const key_length = strlen(key);
-    char const **it = envs;
-    for (; (it) && (*it); ++it) {
-        if ((0 == strncmp(*it, key, key_length)) &&
-            (strlen(*it) > key_length) && ('=' == (*it)[key_length]))
-            break;
-    }
-    // allocate a environment entry
-    size_t const value_length = strlen(value);
-    size_t const env_length = key_length + value_length + 2;
-    char *env = malloc(env_length);
-    if (0 == env) {
-        perror("bear: malloc [in env_update]");
-        exit(EXIT_FAILURE);
-    }
-    if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
-        perror("bear: snprintf");
-        exit(EXIT_FAILURE);
-    }
-    // replace or append the environment entry
-    if (it && *it) {
-        free((void *)*it);
-        *it = env;
-	return envs;
-    }
-    return bear_strings_append(envs, env);
-}
-
-static char **bear_get_environment() {
-#if defined HAVE_NSGETENVIRON
-    return *_NSGetEnviron();
-#else
-    return environ;
-#endif
-}
-
-/* util methods to deal with string arrays. environment and process arguments
- * are both represented as string arrays. */
-
-static char const **bear_strings_build(char const *const arg, va_list *args) {
-    char const **result = 0;
-    size_t size = 0;
-    for (char const *it = arg; it; it = va_arg(*args, char const *)) {
-        result = realloc(result, (size + 1) * sizeof(char const *));
-        if (0 == result) {
-            perror("bear: realloc");
-            exit(EXIT_FAILURE);
-        }
-        char const *copy = strdup(it);
-        if (0 == copy) {
-            perror("bear: strdup");
-            exit(EXIT_FAILURE);
-        }
-        result[size++] = copy;
-    }
-    result = realloc(result, (size + 1) * sizeof(char const *));
-    if (0 == result) {
-        perror("bear: realloc");
-        exit(EXIT_FAILURE);
-    }
-    result[size++] = 0;
-
-    return result;
-}
-
-static char const **bear_strings_copy(char const **const in) {
-    size_t const size = bear_strings_length(in);
-
-    char const **const result = malloc((size + 1) * sizeof(char const *));
-    if (0 == result) {
-        perror("bear: malloc");
-        exit(EXIT_FAILURE);
-    }
-
-    char const **out_it = result;
-    for (char const *const *in_it = in; (in_it) && (*in_it);
-         ++in_it, ++out_it) {
-        *out_it = strdup(*in_it);
-        if (0 == *out_it) {
-            perror("bear: strdup");
-            exit(EXIT_FAILURE);
-        }
-    }
-    *out_it = 0;
-    return result;
-}
-
-static char const **bear_strings_append(char const **const in,
-                                        char const *const e) {
-    size_t size = bear_strings_length(in);
-    char const **result = realloc(in, (size + 2) * sizeof(char const *));
-    if (0 == result) {
-        perror("bear: realloc");
-        exit(EXIT_FAILURE);
-    }
-    result[size++] = e;
-    result[size++] = 0;
-    return result;
-}
-
-static size_t bear_strings_length(char const *const *const in) {
-    size_t result = 0;
-    for (char const *const *it = in; (it) && (*it); ++it)
-        ++result;
-    return result;
-}
-
-static void bear_strings_release(char const **in) {
-    for (char const *const *it = in; (it) && (*it); ++it) {
-        free((void *)*it);
-    }
-    free((void *)in);
-}

diff  --git a/clang/tools/scan-build-py/bin/analyze-c++ b/clang/tools/scan-build-py/libexec/analyze-c++
similarity index 86%
rename from clang/tools/scan-build-py/bin/analyze-c++
rename to clang/tools/scan-build-py/libexec/analyze-c++
index 564e2abf554a3..a280b2fb4ddaf 100755
--- a/clang/tools/scan-build-py/bin/analyze-c++
+++ b/clang/tools/scan-build-py/libexec/analyze-c++
@@ -7,7 +7,8 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
+
 
 from libscanbuild.analyze import analyze_compiler_wrapper
 sys.exit(analyze_compiler_wrapper())

diff  --git a/clang/tools/scan-build-py/bin/analyze-cc b/clang/tools/scan-build-py/libexec/analyze-cc
similarity index 86%
rename from clang/tools/scan-build-py/bin/analyze-cc
rename to clang/tools/scan-build-py/libexec/analyze-cc
index 564e2abf554a3..36bbcd93f9871 100755
--- a/clang/tools/scan-build-py/bin/analyze-cc
+++ b/clang/tools/scan-build-py/libexec/analyze-cc
@@ -7,7 +7,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.analyze import analyze_compiler_wrapper
 sys.exit(analyze_compiler_wrapper())

diff  --git a/clang/tools/scan-build-py/bin/intercept-c++ b/clang/tools/scan-build-py/libexec/intercept-c++
similarity index 86%
rename from clang/tools/scan-build-py/bin/intercept-c++
rename to clang/tools/scan-build-py/libexec/intercept-c++
index 4230c8035d22b..9e541a180d6b4 100755
--- a/clang/tools/scan-build-py/bin/intercept-c++
+++ b/clang/tools/scan-build-py/libexec/intercept-c++
@@ -7,7 +7,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.intercept import intercept_compiler_wrapper
 sys.exit(intercept_compiler_wrapper())

diff  --git a/clang/tools/scan-build-py/bin/intercept-cc b/clang/tools/scan-build-py/libexec/intercept-cc
similarity index 86%
rename from clang/tools/scan-build-py/bin/intercept-cc
rename to clang/tools/scan-build-py/libexec/intercept-cc
index 4230c8035d22b..9e541a180d6b4 100755
--- a/clang/tools/scan-build-py/bin/intercept-cc
+++ b/clang/tools/scan-build-py/libexec/intercept-cc
@@ -7,7 +7,7 @@
 import sys
 import os.path
 this_dir = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.dirname(this_dir))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
 
 from libscanbuild.intercept import intercept_compiler_wrapper
 sys.exit(intercept_compiler_wrapper())

diff  --git a/clang/tools/scan-build-py/tests/__init__.py b/clang/tools/scan-build-py/tests/__init__.py
index 9efd16022651f..45d5b8d7cc025 100644
--- a/clang/tools/scan-build-py/tests/__init__.py
+++ b/clang/tools/scan-build-py/tests/__init__.py
@@ -3,6 +3,12 @@
 # See https://llvm.org/LICENSE.txt for license information.
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
+import os
+import sys
+
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(os.path.dirname(this_dir), 'lib'))
+
 import unittest
 
 import tests.unit

diff  --git a/clang/tools/scan-build-py/tests/functional/cases/__init__.py b/clang/tools/scan-build-py/tests/functional/cases/__init__.py
index 7ac3456f98afd..e8c490add6c61 100644
--- a/clang/tools/scan-build-py/tests/functional/cases/__init__.py
+++ b/clang/tools/scan-build-py/tests/functional/cases/__init__.py
@@ -22,7 +22,7 @@ def load_tests(loader, suite, pattern):
 
 def make_args(target):
     this_dir, _ = os.path.split(__file__)
-    path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+    path = os.path.abspath(os.path.join(this_dir, '..', 'src'))
     return ['make', 'SRCDIR={}'.format(path), 'OBJDIR={}'.format(target), '-f',
             os.path.join(path, 'build', 'Makefile')]
 

diff  --git a/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py b/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
index b0fec3db0c9e3..d6bf572481a34 100644
--- a/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
+++ b/clang/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
@@ -43,7 +43,7 @@ def read_json(filename):
 
     def test_all_exec_calls(self):
         this_dir, _ = os.path.split(__file__)
-        source_dir = os.path.normpath(os.path.join(this_dir, '..', 'exec'))
+        source_dir = os.path.abspath(os.path.join(this_dir, '..', 'exec'))
         with libear.TemporaryDirectory() as tmp_dir:
             expected, result = run(source_dir, tmp_dir)
             self.assertEqualJson(expected, result)

diff  --git a/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py b/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
index 90db89f626360..3b52d852fbf23 100644
--- a/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
+++ b/clang/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
@@ -15,7 +15,7 @@
 def prepare_cdb(name, target_dir):
     target_file = 'build_{0}.json'.format(name)
     this_dir, _ = os.path.split(__file__)
-    path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+    path = os.path.abspath(os.path.join(this_dir, '..', 'src'))
     source_dir = os.path.join(path, 'compilation_database')
     source_file = os.path.join(source_dir, target_file + '.in')
     target_file = os.path.join(target_dir, 'compile_commands.json')

diff  --git a/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py b/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
index 62e369c7c61e4..aa244631bce9f 100644
--- a/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
+++ b/clang/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
@@ -17,7 +17,7 @@ class OutputDirectoryTest(unittest.TestCase):
     @staticmethod
     def run_analyzer(outdir, args, cmd):
         return check_call_and_report(
-            ['scan-build', '--intercept-first', '-o', outdir] + args,
+            ['scan-build-py', '--intercept-first', '-o', outdir] + args,
             cmd)
 
     def test_regular_keeps_report_dir(self):
@@ -49,7 +49,7 @@ def test_interposition_works(self):
         with libear.TemporaryDirectory() as tmpdir:
             make = make_args(tmpdir) + ['build_regular']
             outdir = check_call_and_report(
-                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+                ['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
                 make)
 
             self.assertTrue(os.path.isdir(outdir))
@@ -59,7 +59,7 @@ def test_intercept_wrapper_works(self):
         with libear.TemporaryDirectory() as tmpdir:
             make = make_args(tmpdir) + ['build_regular']
             outdir = check_call_and_report(
-                ['scan-build', '--plist', '-o', tmpdir, '--intercept-first',
+                ['scan-build-py', '--plist', '-o', tmpdir, '--intercept-first',
                  '--override-compiler'],
                 make)
 
@@ -70,7 +70,7 @@ def test_intercept_library_works(self):
         with libear.TemporaryDirectory() as tmpdir:
             make = make_args(tmpdir) + ['build_regular']
             outdir = check_call_and_report(
-                ['scan-build', '--plist', '-o', tmpdir, '--intercept-first'],
+                ['scan-build-py', '--plist', '-o', tmpdir, '--intercept-first'],
                 make)
 
             self.assertTrue(os.path.isdir(outdir))
@@ -89,21 +89,21 @@ def compile_empty_source_file(target_dir, is_cxx):
     def test_interposition_cc_works(self):
         with libear.TemporaryDirectory() as tmpdir:
             outdir = check_call_and_report(
-                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+                ['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
                 self.compile_empty_source_file(tmpdir, False))
             self.assertEqual(self.get_plist_count(outdir), 1)
 
     def test_interposition_cxx_works(self):
         with libear.TemporaryDirectory() as tmpdir:
             outdir = check_call_and_report(
-                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+                ['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler'],
                 self.compile_empty_source_file(tmpdir, True))
             self.assertEqual(self.get_plist_count(outdir), 1)
 
     def test_intercept_cc_works(self):
         with libear.TemporaryDirectory() as tmpdir:
             outdir = check_call_and_report(
-                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+                ['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler',
                  '--intercept-first'],
                 self.compile_empty_source_file(tmpdir, False))
             self.assertEqual(self.get_plist_count(outdir), 1)
@@ -111,7 +111,7 @@ def test_intercept_cc_works(self):
     def test_intercept_cxx_works(self):
         with libear.TemporaryDirectory() as tmpdir:
             outdir = check_call_and_report(
-                ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+                ['scan-build-py', '--plist', '-o', tmpdir, '--override-compiler',
                  '--intercept-first'],
                 self.compile_empty_source_file(tmpdir, True))
             self.assertEqual(self.get_plist_count(outdir), 1)

diff  --git a/clang/tools/scan-build-py/tests/unit/test_analyze.py b/clang/tools/scan-build-py/tests/unit/test_analyze.py
index 47d38a4da2cdb..823fcab9f47e5 100644
--- a/clang/tools/scan-build-py/tests/unit/test_analyze.py
+++ b/clang/tools/scan-build-py/tests/unit/test_analyze.py
@@ -18,9 +18,9 @@ class ReportDirectoryTest(unittest.TestCase):
     # scan-build can be easily matched up to compare results.
     def test_directory_name_comparison(self):
         with libear.TemporaryDirectory() as tmpdir, \
-             sut.report_directory(tmpdir, False) as report_dir1, \
-             sut.report_directory(tmpdir, False) as report_dir2, \
-             sut.report_directory(tmpdir, False) as report_dir3:
+             sut.report_directory(tmpdir, False, 'html') as report_dir1, \
+             sut.report_directory(tmpdir, False, 'html') as report_dir2, \
+             sut.report_directory(tmpdir, False, 'html') as report_dir3:
             self.assertLess(report_dir1, report_dir2)
             self.assertLess(report_dir2, report_dir3)
 


        


More information about the cfe-commits mailing list