Add ccc-analyzer/cxx-analyzer

Wrappers invoked by build system "WITH_STATIC_ANALYZER=1 m/mm/mmm/mma/mmma ..."
in the following format:

    ccc-analyzer ARCH LOCAL_CC ...

Under WITH_SYNTAX_CHECK=1, m/mm/mmm/mma/mmma wrap "make" with
"tools/scan-build/scan-build" which utillizes "clang --analyze"
for static code analyses.  Script scan-build interposes on compiler
with CC/CXX ignored by the Android build system unfortunately.
Instead, Android build system recognizes WITH_SYNTAX_CHECK and
replace LOCAL_CC/LOCAL_CXX with our own ccc-syntax/cxx-syntax,
which in turn setup the following env. vars expected by
tools/scan-build/{ccc,c++}-analyzer

Also fix tools/scan-build
1. ccc-analyzer to sandwich args passed to clang with
   CLANG_CFLAGS and CLANG_CFLAGS_END, otherwise clang may not
   succeed with right --target and headers in prebuilts/gcc
2. scan-build to accept "--top=Android_top_dir" soley to display
   full path of scan-view to open report should analyzer fail.

Change-Id: I4ec40d5174fc9af380d20898eb1d0c7b8a14ce11
diff --git a/bin/ccc-analyzer b/bin/ccc-analyzer
new file mode 100755
index 0000000..693f049
--- /dev/null
+++ b/bin/ccc-analyzer
@@ -0,0 +1,112 @@
+#!/bin/sh
+
+# This script is invoked by Android build system "WITH_SYNTAX_CHECK=1 m/mm/mmm ..." and
+# accepts command line in the following format:
+#
+#    ccc-analyzer ARCH LOCAL_CC ...
+#
+# Under WITH_SYNTAX_CHECK=1, m/mm/mmm/mma/mmma wrap "make" with "tools/scan-build/scan-build"
+# which utillizes "clang --analyze" for static code analyses.  Script scan-build interposes
+# on compiler with CC/CXX ignored by the Android build system unfortunately.  Instead,
+# Android build system recognizes WITH_SYNTAX_CHECK and replace LOCAL_CC with our own ccc-syntax,
+# which in turn setup the following env. vars expected by tools/scan-build/ccc-analyzer
+#
+#   CCC_CC: The origianl LOCAL_CC which does the real compilation and code-gen
+#   CLANG: The clang compiler which run code analyses
+#
+# Our own ccc-syntax also export the following, and tools/scan-build/ccc-analyzer is slightly
+# modified to prefix/append them in options passed to clang for successful compilation
+#
+#   CLANG_FLAGS: Flags to set correct target, be compatible with gcc, etc
+#   CLANG_FLAGS_END:  Flags to override "$@"
+#
+
+ARCH="$1"
+LOCAL_CC="$2"
+shift ; shift
+
+# Turn off warning about unused options
+CLANG_FLAGS="-Qunused-arguments"
+
+# Turn off unknown warning options
+CLANG_FLAGS="$CLANG_FLAGS -Wno-unknown-warning-option"
+
+# Define WITH_SYNTAX_CHECK for code wish to behave differently when check
+CLANG_FLAGS="$CLANG_FLAGS -DWITH_SYNTAX_CHECK"
+
+# If LOCAL_CC is not clang and not compiling in c++ mode, turn on -std=gnu89 by default
+# and let "$@" later override it, if any
+test "$LOCAL_CC" != "${LOCAL_CC%-x c++}" -o "$LOCAL_CC" = "${LOCAL_CC%-xc++}" && cxx_mode=true
+if [ "$LOCAL_CC" = "${LOCAL_CC%clang}" -a "$cxx_mode" != "true" ] ; then
+    CLANG_FLAGS="$CLANG_FLAGS -std=gnu89"
+fi
+
+# Turn off warnings which aren't useful in this context
+CLANG_FLAGS="$CLANG_FLAGS -Wno-ignored-attributes -Wno-pedantic -Wno-builtin-requires-header -Wno-gnu -Wno-gnu-designator -Wno-knr-promoted-parameter"
+
+if [ "$ARCH" != "host" ]; then
+    # Add target to get proper pre-defined preprocessor symbols/macros.
+    case $ARCH in
+        arm) CLANG_FLAGS="$CLANG_FLAGS -target armv5te-none-linux-androideabi"
+            ;;
+        mips) CLANG_FLAGS="$CLANG_FLAGS -target mipsel-none-linux-android"
+            ;;
+        x86) CLANG_FLAGS="$CLANG_FLAGS -target i686-none-linux-android"
+            ;;
+    esac
+    if [ "$LOCAL_CC" != "${LOCAL_CC%clang*}" ]; then
+        # Don't look for its own lib/clang/3.3/include when LOCAL_CC is clang
+        # which is rebuilt from source w/o installing its include as well
+        CLANG_FLAGS="$CLANG_FLAGS -nostdinc"
+    fi
+else
+    # Note that unlike target flags where Android build system explicitly specify
+    # everything in command line, host tools have their own sysroot and --sysroot
+    # isn't explicitly added in the commmand line.  Likelywise for other gcc implicit
+    # search directories.
+    #
+    # We can query search paths by doing "gcc -v" and parsing the output with
+    # sed -n '1,/BEGIN/!{ /END/,/BEING/!p; }' (*1), but forking gcc here adds overhead.
+    # Because host tool refresh only once 1-2 year, here we hard-code the path obtained by (*2).
+    # ToDo: The build system can do it once for each module, although it still needs to
+    # prepare both -m32 and -m64 versions, anding 2 more args in additional to $ARCH
+    # and $LOCAL_CC
+    #
+    # (*1) as described in http://sed.sourceforge.net/sedfaq4.html#s4.24
+    # (*2) prebuilts/tools/gcc-sdk/gcc -m64 -v -E - < /dev/null 2>&1 | \
+    #         sed -n '1,/> search starts here/!{ /End of search list/,/> search starts here/!p; }' |\
+    #         sed -e 's/^/-I/'
+    #      Likewise for -m32
+    #
+    # Please refer to prebuilts/tools/gcc-sdk/gcc for similar trick to determine
+    # bitness
+    options=" ${@} "   # sentinel prefix/suffix space to simplify pattern match below
+    suffix_m32=${options##* -m32 }    # suffix after the last -m32
+    suffix_m64=${options##* -m64 }    # suffix after the last -m64
+    len_m32=${#suffix_m32}            # length of suffix after the last -m32
+    len_m64=${#suffix_m64}            # length of suffix after the last -m64
+    if [ $len_m32 -ge $len_m64 ] ; then
+        CLANG_FLAGS_END="\
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/lib/gcc/x86_64-linux/4.6.x-google/include \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/lib/gcc/x86_64-linux/4.6.x-google/include-fixed \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/x86_64-linux/include \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/sysroot/usr/include"
+    else
+        CLANG_FLAGS_END="\
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/lib/gcc/i686-linux/4.6.x-google/include \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/lib/gcc/i686-linux/4.6.x-google/include-fixed \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/i686-linux/include \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/sysroot/usr/include"
+    fi
+fi
+
+# Turn off warnings (at the end) on features we exploit
+CLANG_FLAGS_END="$CLANG_FLAGS_END -Wno-return-type-c-linkage"
+
+# Call the real ccc-analyzer.  Note that tools/scan-build/ccc-analyzer "exec" $CCC_CC,
+# which is LOCAL_CC w/o optional ccache (in "ccache gcc" format)
+export CCC_CC="${LOCAL_CC##* }"
+export CLANG="`dirname $0`/clang"
+export CLANG_FLAGS
+export CLANG_FLAGS_END
+`dirname $0`/../tools/scan-build/ccc-analyzer "$@"
diff --git a/bin/ccc-syntax b/bin/ccc-syntax
index ab8dc8c..1069f10 100755
--- a/bin/ccc-syntax
+++ b/bin/ccc-syntax
@@ -54,6 +54,7 @@
         mips) CLANG_FLAGS="$CLANG_FLAGS -target mipsel-none-linux-android"
             ;;
         x86) CLANG_FLAGS="$CLANG_FLAGS -target i686-none-linux-android"
+            ;;
     esac
     if [ "$LOCAL_CC" != "${LOCAL_CC%clang*}" ]; then
         # Don't look for its own lib/clang/3.3/include when LOCAL_CC is clang
diff --git a/bin/cxx-analyzer b/bin/cxx-analyzer
new file mode 100755
index 0000000..8f89c0c
--- /dev/null
+++ b/bin/cxx-analyzer
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+# This script is invoked by Android build system "WITH_SYNTAX_CHECK=1 m/mm/mmm ..." and
+# accepts command line in the following format:
+#
+#    ccc-analyzer ARCH LOCAL_CXX ...
+#
+# Under WITH_SYNTAX_CHECK=1, m/mm/mmm/mma/mmma wrap "make" with "tools/scan-build/scan-build"
+# which utillizes "clang++ --analyze" for static code analyses.  Script scan-build interposes
+# on compiler with CC/CXX ignored by the Android build system unfortunately.  Instead,
+# Android build system recognizes WITH_SYNTAX_CHECK and replace LOCAL_CXX with our own cxx-syntax,
+# which in turn setup the following env. vars expected by tools/scan-build/c++-analyzer
+#
+#   CCC_CXX: The origianl LOCAL_CXX which does the real compilation and code-gen
+#   CLANG_CXX: The clang++ compiler which run code analyses
+#
+# Our own cxx-syntax also export the following, and tools/scan-build/ccc-analyzer is slightly
+# modified to prefix/append them in options passed to clang++ for successful compilation
+#
+#   CLANG_FLAGS: Flags to set correct target, be compatible with gcc, etc
+#   CLANG_FLAGS_END:  Flags to override "$@"
+#
+
+ARCH="$1"
+LOCAL_CXX="$2"
+shift ; shift
+
+# Turn off warning about unused options
+CLANG_FLAGS="-Qunused-arguments"
+
+# Turn off unknown warning options
+CLANG_FLAGS="$CLANG_FLAGS -Wno-unknown-warning-option"
+
+# Define WITH_SYNTAX_CHECK for code wish to behave differently when check
+CLANG_FLAGS="$CLANG_FLAGS -DWITH_SYNTAX_CHECK"
+
+# Ignore C standard like -std=gnu99 in LOCAL_CFLAGS but get
+# passed for C++ compilation by build system
+CLANG_FLAGS="$CLANG_FLAGS -Qignore-c-std-not-allowed-with-cplusplus"
+
+# Turn off warnings which aren't useful in this context
+CLANG_FLAGS="$CLANG_FLAGS -Wno-ignored-attributes -Wno-pedantic -Wno-builtin-requires-header -Wno-gnu -Wno-gnu-designator -Wno-knr-promoted-parameter"
+
+if [ "$ARCH" != "host" ]; then
+    # Add target to get proper pre-defined preprocessor symbols/macros.
+    case $ARCH in
+        arm) CLANG_FLAGS="$CLANG_FLAGS -target armv5te-none-linux-androideabi"
+            ;;
+        mips) CLANG_FLAGS="$CLANG_FLAGS -target mipsel-none-linux-android"
+            ;;
+        x86) CLANG_FLAGS="$CLANG_FLAGS -target i686-none-linux-android"
+            ;;
+    esac
+    if [ "$LOCAL_CXX" != "${LOCAL_CXX%clang++*}" ]; then
+        # Don't look for its own lib/clang/3.3/include when LOCAL_CXX is clang
+        # which is rebuilt from source w/o installing its include as well
+        CLANG_FLAGS="$CLANG_FLAGS -nostdinc"
+    fi
+else
+    # Note that unlike target flags where Android build system explicitly specify
+    # everything in command line, host tools have their own sysroot and --sysroot
+    # isn't explicitly added in the commmand line.  Likelywise for other gcc implicit
+    # search directories.
+    #
+    # We can query search paths by doing "g++ -v" and parsing the output with
+    # sed -n '1,/BEGIN/!{ /END/,/BEING/!p; }' (*1), but forking gcc here adds overhead.
+    # Because host tool refresh only once 1-2 year, here we hard-code the path obtained by (*2).
+    # ToDo: The build system can do it once for each module, although it still needs to
+    # prepare both -m32 and -m64 versions, anding 2 more args in additional to $ARCH
+    # and $LOCAL_CXX
+    #
+    # (*1) as described in http://sed.sourceforge.net/sedfaq4.html#s4.24
+    # (*2) prebuilts/tools/gcc-sdk/g++ -m64 -v -E - < /dev/null 2>&1 | \
+    #         sed -n '1,/> search starts here/!{ /End of search list/,/> search starts here/!p; }' |\
+    #         sed -e 's/^/-I/'
+    #      Likewise for -m32
+    #
+    # Please refer to prebuilts/tools/gcc-sdk/gcc for similar trick to determine
+    # bitness
+    options=" ${@} "   # sentinel prefix/suffix space to simplify pattern match below
+    suffix_m32=${options##* -m32 }    # suffix after the last -m32
+    suffix_m64=${options##* -m64 }    # suffix after the last -m64
+    len_m32=${#suffix_m32}            # length of suffix after the last -m32
+    len_m64=${#suffix_m64}            # length of suffix after the last -m64
+    if [ $len_m32 -ge $len_m64 ] ; then
+        CLANG_FLAGS_END="\
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/x86_64-linux/include/c++/4.6.x-google \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/x86_64-linux/include/c++/4.6.x-google/x86_64-linux \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/x86_64-linux/include/c++/4.6.x-google/backward \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/lib/gcc/x86_64-linux/4.6.x-google/include \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/lib/gcc/x86_64-linux/4.6.x-google/include-fixed \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/x86_64-linux/include \
+-I prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/sysroot/usr/include"
+    else
+        CLANG_FLAGS_END="\
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/i686-linux/include/c++/4.6.x-google \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/i686-linux/include/c++/4.6.x-google/i686-linux \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/i686-linux/include/c++/4.6.x-google/backward \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/lib/gcc/i686-linux/4.6.x-google/include \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/lib/gcc/i686-linux/4.6.x-google/include-fixed \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/i686-linux/include \
+-I prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/sysroot/usr/include"
+    fi
+fi
+
+# Turn off warnings (at the end) on features we exploit
+CLANG_FLAGS_END="$CLANG_FLAGS_END -Wno-return-type-c-linkage"
+
+# Call the real c++-analyzer.  Note that tools/scan-build/c++-analyzer "exec" $CCC_CXX,
+# which is LOCAL_CXX w/o optional ccache (in "ccache g++" format)
+export CCC_CXX="${LOCAL_CXX##* }"
+export CLANG_CXX="`dirname $0`/clang++"
+export CLANG_FLAGS
+export CLANG_FLAGS_END
+`dirname $0`/../tools/scan-build/c++-analyzer "$@"
diff --git a/bin/cxx-syntax b/bin/cxx-syntax
index 839dace..7ea7791 100755
--- a/bin/cxx-syntax
+++ b/bin/cxx-syntax
@@ -51,6 +51,7 @@
         mips) CLANG_FLAGS="$CLANG_FLAGS -target mipsel-none-linux-android"
             ;;
         x86) CLANG_FLAGS="$CLANG_FLAGS -target i686-none-linux-android"
+            ;;
     esac
     if [ "$LOCAL_CXX" != "${LOCAL_CXX%clang++*}" ]; then
         # Don't look for its own lib/clang/3.3/include when LOCAL_CXX is clang
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 5f63148..c6b0fae 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -27,6 +27,8 @@
 
 my $Compiler;
 my $Clang;
+my @ClangFlags;
+my @ClangFlagsEnd;
 my $DefaultCCompiler;
 my $DefaultCXXCompiler;
 
@@ -53,6 +55,9 @@
   if (!defined $Clang) { $Clang = 'clang'; }
 }
 
+@ClangFlags = quotewords('\s+', 0, $ENV{'CLANG_FLAGS'});
+@ClangFlagsEnd = quotewords('\s+', 0, $ENV{'CLANG_FLAGS_END'});
+
 ##===----------------------------------------------------------------------===##
 # Cleanup.
 ##===----------------------------------------------------------------------===##
@@ -111,14 +116,14 @@
   my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX",
                                  SUFFIX => GetPPExt($Lang),
                                  DIR => $Dir);
-  system $Clang, @$Args, "-E", "-o", $PPFile;
+  system $Clang, @ClangFlags, @$Args, @ClangFlagsEnd, "-E", "-o", $PPFile;
   close ($PPH);
   
   # Create the info file.
   open (OUT, ">", "$PPFile.info.txt") or die "Cannot open $PPFile.info.txt\n";
   print OUT abs_path($file), "\n";
   print OUT "$ErrorType\n";
-  print OUT "@$Args\n";
+  print OUT "@ClangFlags @$Args @ClangFlagsEnd\n";
   close OUT;
   `uname -a >> $PPFile.info.txt 2>&1`;
   `$Compiler -v >> $PPFile.info.txt 2>&1`;
@@ -140,7 +145,7 @@
     close FROM_CHILD;
     open(STDOUT,">&", \*TO_PARENT);
     open(STDERR,">&", \*TO_PARENT);
-    exec $Clang, "-###", $mode, @$Args;
+    exec $Clang, "-###", $mode, @ClangFlags, @$Args, @ClangFlagsEnd;
   }  
   close(TO_PARENT);
   my $line;
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 4590279..fbef89a 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -27,6 +27,7 @@
 my $Prog = "scan-build";
 my $BuildName;
 my $BuildDate;
+my $Top;
 
 my $TERM = $ENV{'TERM'};
 my $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT
@@ -845,7 +846,7 @@
   my $Num = scalar(@Index);
   Diag("$Num bugs found.\n");
   if ($Num > 0 && -r "$Dir/index.html") {
-    Diag("Run 'scan-view $Dir' to examine bug reports.\n");
+      Diag("Run '$Top/prebuilts/clang/linux-x86/host/3.3/tools/scan-view/scan-view $Dir' to examine bug reports.\n");
   }
   
   DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
@@ -1526,6 +1527,21 @@
     $OverrideCompiler = 1;
     next;
   }
+
+  if ($arg =~ /^--top(=(.+))?$/) {
+    shift @ARGV;
+
+    if (!defined $2 || $2 eq "") {
+      if (!@ARGV) {
+        DieDiag("'--top' option requires a directory.\n");
+      }
+      $Top = shift @ARGV;
+    }
+    else {
+      $Top = $2;
+    }
+    next;
+  }
   
   DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);