Import prebuilt clang toolchain for linux.
diff --git a/linux-x64/clang/share/clang/bash-autocomplete.sh b/linux-x64/clang/share/clang/bash-autocomplete.sh
new file mode 100755
index 0000000..3872dd2
--- /dev/null
+++ b/linux-x64/clang/share/clang/bash-autocomplete.sh
@@ -0,0 +1,64 @@
+# Please add "source /path/to/bash-autocomplete.sh" to your .bashrc to use this.
+
+_clang_filedir()
+{
+ # _filedir function provided by recent versions of bash-completion package is
+ # better than "compgen -f" because the former honors spaces in pathnames while
+ # the latter doesn't. So we use compgen only when _filedir is not provided.
+ _filedir 2> /dev/null || COMPREPLY=( $( compgen -f ) )
+}
+
+_clang()
+{
+ local cur prev words cword arg flags w1 w2
+ # If latest bash-completion is not supported just initialize COMPREPLY and
+ # initialize variables by setting manualy.
+ _init_completion -n 2> /dev/null
+ if [[ "$?" != 0 ]]; then
+ COMPREPLY=()
+ cword=$COMP_CWORD
+ cur="${COMP_WORDS[$cword]}"
+ fi
+
+ w1="${COMP_WORDS[$cword - 1]}"
+ if [[ $cword > 1 ]]; then
+ w2="${COMP_WORDS[$cword - 2]}"
+ fi
+
+ # Pass all the current command-line flags to clang, so that clang can handle
+ # these internally.
+ # '=' is separated differently by bash, so we have to concat them without ','
+ for i in `seq 1 $cword`; do
+ if [[ $i == $cword || "${COMP_WORDS[$(($i+1))]}" == '=' ]]; then
+ arg="$arg${COMP_WORDS[$i]}"
+ else
+ arg="$arg${COMP_WORDS[$i]},"
+ fi
+ done
+
+ # expand ~ to $HOME
+ eval local path=${COMP_WORDS[0]}
+ flags=$( "$path" --autocomplete="$arg" 2>/dev/null | sed -e 's/\t.*//' )
+ # If clang is old that it does not support --autocomplete,
+ # fall back to the filename completion.
+ if [[ "$?" != 0 ]]; then
+ _clang_filedir
+ return
+ fi
+
+ # When clang does not emit any possible autocompletion, or user pushed tab after " ",
+ # just autocomplete files.
+ if [[ "$flags" == "$(echo -e '\n')" ]]; then
+ # If -foo=<tab> and there was no possible values, autocomplete files.
+ [[ "$cur" == '=' || "$cur" == -*= ]] && cur=""
+ _clang_filedir
+ elif [[ "$cur" == '=' ]]; then
+ COMPREPLY=( $( compgen -W "$flags" -- "") )
+ else
+ # Bash automatically appends a space after '=' by default.
+ # Disable it so that it works nicely for options in the form of -foo=bar.
+ [[ "${flags: -1}" == '=' ]] && compopt -o nospace 2> /dev/null
+ COMPREPLY=( $( compgen -W "$flags" -- "$cur" ) )
+ fi
+}
+complete -F _clang clang
diff --git a/linux-x64/clang/share/clang/clang-format-bbedit.applescript b/linux-x64/clang/share/clang/clang-format-bbedit.applescript
new file mode 100755
index 0000000..fa88fe9
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-format-bbedit.applescript
@@ -0,0 +1,27 @@
+-- In this file, change "/path/to/" to the path where you installed clang-format
+-- and save it to ~/Library/Application Support/BBEdit/Scripts. You can then
+-- select the script from the Script menu and clang-format will format the
+-- selection. Note that you can rename the menu item by renaming the script, and
+-- can assign the menu item a keyboard shortcut in the BBEdit preferences, under
+-- Menus & Shortcuts.
+on urlToPOSIXPath(theURL)
+ return do shell script "python -c \"import urllib, urlparse, sys; print urllib.unquote(urlparse.urlparse(sys.argv[1])[2])\" " & quoted form of theURL
+end urlToPOSIXPath
+
+tell application "BBEdit"
+ set selectionOffset to characterOffset of selection
+ set selectionLength to length of selection
+ set fileURL to URL of text document 1
+end tell
+
+set filePath to urlToPOSIXPath(fileURL)
+set newContents to do shell script "/path/to/clang-format -offset=" & selectionOffset & " -length=" & selectionLength & " " & quoted form of filePath
+
+tell application "BBEdit"
+ -- "set contents of text document 1 to newContents" scrolls to the bottom while
+ -- replacing a selection flashes a bit but doesn't affect the scroll position.
+ set currentLength to length of contents of text document 1
+ select characters 1 thru currentLength of text document 1
+ set text of selection to newContents
+ select characters selectionOffset thru (selectionOffset + selectionLength - 1) of text document 1
+end tell
diff --git a/linux-x64/clang/share/clang/clang-format-diff.py b/linux-x64/clang/share/clang/clang-format-diff.py
new file mode 100755
index 0000000..ffa30e7
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-format-diff.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+#===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+ClangFormat Diff Reformatter
+============================
+
+This script reads input from a unified diff and reformats all the changed
+lines. This is useful to reformat all the lines touched by a specific patch.
+Example usage for git/svn users:
+
+ git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i
+ svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
+
+"""
+
+import argparse
+import difflib
+import re
+import string
+import subprocess
+import StringIO
+import sys
+
+
+def main():
+ parser = argparse.ArgumentParser(description=
+ 'Reformat changed lines in diff. Without -i '
+ 'option just output the diff that would be '
+ 'introduced.')
+ parser.add_argument('-i', action='store_true', default=False,
+ help='apply edits to files instead of displaying a diff')
+ parser.add_argument('-p', metavar='NUM', default=0,
+ help='strip the smallest prefix containing P slashes')
+ parser.add_argument('-regex', metavar='PATTERN', default=None,
+ help='custom pattern selecting file paths to reformat '
+ '(case sensitive, overrides -iregex)')
+ parser.add_argument('-iregex', metavar='PATTERN', default=
+ r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|ts|proto'
+ r'|protodevel|java)',
+ help='custom pattern selecting file paths to reformat '
+ '(case insensitive, overridden by -regex)')
+ parser.add_argument('-sort-includes', action='store_true', default=False,
+ help='let clang-format sort include blocks')
+ parser.add_argument('-v', '--verbose', action='store_true',
+ help='be more verbose, ineffective without -i')
+ parser.add_argument('-style',
+ help='formatting style to apply (LLVM, Google, Chromium, '
+ 'Mozilla, WebKit)')
+ parser.add_argument('-binary', default='clang-format',
+ help='location of binary to use for clang-format')
+ args = parser.parse_args()
+
+ # Extract changed lines for each file.
+ filename = None
+ lines_by_file = {}
+ for line in sys.stdin:
+ match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
+ if match:
+ filename = match.group(2)
+ if filename == None:
+ continue
+
+ if args.regex is not None:
+ if not re.match('^%s$' % args.regex, filename):
+ continue
+ else:
+ if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
+ continue
+
+ match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
+ if match:
+ start_line = int(match.group(1))
+ line_count = 1
+ if match.group(3):
+ line_count = int(match.group(3))
+ if line_count == 0:
+ continue
+ end_line = start_line + line_count - 1;
+ lines_by_file.setdefault(filename, []).extend(
+ ['-lines', str(start_line) + ':' + str(end_line)])
+
+ # Reformat files containing changes in place.
+ for filename, lines in lines_by_file.iteritems():
+ if args.i and args.verbose:
+ print 'Formatting', filename
+ command = [args.binary, filename]
+ if args.i:
+ command.append('-i')
+ if args.sort_includes:
+ command.append('-sort-includes')
+ command.extend(lines)
+ if args.style:
+ command.extend(['-style', args.style])
+ p = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=None, stdin=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ if p.returncode != 0:
+ sys.exit(p.returncode);
+
+ if not args.i:
+ with open(filename) as f:
+ code = f.readlines()
+ formatted_code = StringIO.StringIO(stdout).readlines()
+ diff = difflib.unified_diff(code, formatted_code,
+ filename, filename,
+ '(before formatting)', '(after formatting)')
+ diff_string = string.join(diff, '')
+ if len(diff_string) > 0:
+ sys.stdout.write(diff_string)
+
+if __name__ == '__main__':
+ main()
diff --git a/linux-x64/clang/share/clang/clang-format-sublime.py b/linux-x64/clang/share/clang/clang-format-sublime.py
new file mode 100755
index 0000000..16ff56e
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-format-sublime.py
@@ -0,0 +1,58 @@
+# This file is a minimal clang-format sublime-integration. To install:
+# - Change 'binary' if clang-format is not on the path (see below).
+# - Put this file into your sublime Packages directory, e.g. on Linux:
+# ~/.config/sublime-text-2/Packages/User/clang-format-sublime.py
+# - Add a key binding:
+# { "keys": ["ctrl+shift+c"], "command": "clang_format" },
+#
+# With this integration you can press the bound key and clang-format will
+# format the current lines and selections for all cursor positions. The lines
+# or regions are extended to the next bigger syntactic entities.
+#
+# It operates on the current, potentially unsaved buffer and does not create
+# or save any files. To revert a formatting, just undo.
+
+from __future__ import print_function
+import sublime
+import sublime_plugin
+import subprocess
+
+# Change this to the full path if clang-format is not on the path.
+binary = 'clang-format'
+
+# Change this to format according to other formatting styles. See the output of
+# 'clang-format --help' for a list of supported styles. The default looks for
+# a '.clang-format' or '_clang-format' file to indicate the style that should be
+# used.
+style = 'file'
+
+class ClangFormatCommand(sublime_plugin.TextCommand):
+ def run(self, edit):
+ encoding = self.view.encoding()
+ if encoding == 'Undefined':
+ encoding = 'utf-8'
+ regions = []
+ command = [binary, '-style', style]
+ for region in self.view.sel():
+ regions.append(region)
+ region_offset = min(region.a, region.b)
+ region_length = abs(region.b - region.a)
+ command.extend(['-offset', str(region_offset),
+ '-length', str(region_length),
+ '-assume-filename', str(self.view.file_name())])
+ old_viewport_position = self.view.viewport_position()
+ buf = self.view.substr(sublime.Region(0, self.view.size()))
+ p = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ output, error = p.communicate(buf.encode(encoding))
+ if error:
+ print(error)
+ self.view.replace(
+ edit, sublime.Region(0, self.view.size()),
+ output.decode(encoding))
+ self.view.sel().clear()
+ for region in regions:
+ self.view.sel().add(region)
+ # FIXME: Without the 10ms delay, the viewport sometimes jumps.
+ sublime.set_timeout(lambda: self.view.set_viewport_position(
+ old_viewport_position, False), 10)
diff --git a/linux-x64/clang/share/clang/clang-format.el b/linux-x64/clang/share/clang/clang-format.el
new file mode 100755
index 0000000..6c626e0
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-format.el
@@ -0,0 +1,206 @@
+;;; clang-format.el --- Format code using clang-format -*- lexical-binding: t; -*-
+
+;; Keywords: tools, c
+;; Package-Requires: ((cl-lib "0.3"))
+
+;;; Commentary:
+
+;; This package allows to filter code through clang-format to fix its formatting.
+;; clang-format is a tool that formats C/C++/Obj-C code according to a set of
+;; style options, see <http://clang.llvm.org/docs/ClangFormatStyleOptions.html>.
+;; Note that clang-format 3.4 or newer is required.
+
+;; clang-format.el is available via MELPA and can be installed via
+;;
+;; M-x package-install clang-format
+;;
+;; when ("melpa" . "http://melpa.org/packages/") is included in
+;; `package-archives'. Alternatively, ensure the directory of this
+;; file is in your `load-path' and add
+;;
+;; (require 'clang-format)
+;;
+;; to your .emacs configuration.
+
+;; You may also want to bind `clang-format-region' to a key:
+;;
+;; (global-set-key [C-M-tab] 'clang-format-region)
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'xml)
+
+(defgroup clang-format nil
+ "Format code using clang-format."
+ :group 'tools)
+
+(defcustom clang-format-executable
+ (or (executable-find "clang-format")
+ "clang-format")
+ "Location of the clang-format executable.
+
+A string containing the name or the full path of the executable."
+ :group 'clang-format
+ :type '(file :must-match t)
+ :risky t)
+
+(defcustom clang-format-style "file"
+ "Style argument to pass to clang-format.
+
+By default clang-format will load the style configuration from
+a file named .clang-format located in one of the parent directories
+of the buffer."
+ :group 'clang-format
+ :type 'string
+ :safe #'stringp)
+(make-variable-buffer-local 'clang-format-style)
+
+(defun clang-format--extract (xml-node)
+ "Extract replacements and cursor information from XML-NODE."
+ (unless (and (listp xml-node) (eq (xml-node-name xml-node) 'replacements))
+ (error "Expected <replacements> node"))
+ (let ((nodes (xml-node-children xml-node))
+ (incomplete-format (xml-get-attribute xml-node 'incomplete_format))
+ replacements
+ cursor)
+ (dolist (node nodes)
+ (when (listp node)
+ (let* ((children (xml-node-children node))
+ (text (car children)))
+ (cl-case (xml-node-name node)
+ ('replacement
+ (let* ((offset (xml-get-attribute-or-nil node 'offset))
+ (length (xml-get-attribute-or-nil node 'length)))
+ (when (or (null offset) (null length))
+ (error "<replacement> node does not have offset and length attributes"))
+ (when (cdr children)
+ (error "More than one child node in <replacement> node"))
+
+ (setq offset (string-to-number offset))
+ (setq length (string-to-number length))
+ (push (list offset length text) replacements)))
+ ('cursor
+ (setq cursor (string-to-number text)))))))
+
+ ;; Sort by decreasing offset, length.
+ (setq replacements (sort (delq nil replacements)
+ (lambda (a b)
+ (or (> (car a) (car b))
+ (and (= (car a) (car b))
+ (> (cadr a) (cadr b)))))))
+
+ (list replacements cursor (string= incomplete-format "true"))))
+
+(defun clang-format--replace (offset length &optional text)
+ "Replace the region defined by OFFSET and LENGTH with TEXT.
+OFFSET and LENGTH are measured in bytes, not characters. OFFSET
+is a zero-based file offset, assuming ‘utf-8-unix’ coding."
+ (let ((start (clang-format--filepos-to-bufferpos offset 'exact 'utf-8-unix))
+ (end (clang-format--filepos-to-bufferpos (+ offset length) 'exact
+ 'utf-8-unix)))
+ (goto-char start)
+ (delete-region start end)
+ (when text
+ (insert text))))
+
+;; ‘bufferpos-to-filepos’ and ‘filepos-to-bufferpos’ are new in Emacs 25.1.
+;; Provide fallbacks for older versions.
+(defalias 'clang-format--bufferpos-to-filepos
+ (if (fboundp 'bufferpos-to-filepos)
+ 'bufferpos-to-filepos
+ (lambda (position &optional _quality _coding-system)
+ (1- (position-bytes position)))))
+
+(defalias 'clang-format--filepos-to-bufferpos
+ (if (fboundp 'filepos-to-bufferpos)
+ 'filepos-to-bufferpos
+ (lambda (byte &optional _quality _coding-system)
+ (byte-to-position (1+ byte)))))
+
+;;;###autoload
+(defun clang-format-region (start end &optional style assume-file-name)
+ "Use clang-format to format the code between START and END according to STYLE.
+If called interactively uses the region or the current statement if there is no
+no active region. If no STYLE is given uses `clang-format-style'. Use
+ASSUME-FILE-NAME to locate a style config file, if no ASSUME-FILE-NAME is given
+uses the function `buffer-file-name'."
+ (interactive
+ (if (use-region-p)
+ (list (region-beginning) (region-end))
+ (list (point) (point))))
+
+ (unless style
+ (setq style clang-format-style))
+
+ (unless assume-file-name
+ (setq assume-file-name buffer-file-name))
+
+ (let ((file-start (clang-format--bufferpos-to-filepos start 'approximate
+ 'utf-8-unix))
+ (file-end (clang-format--bufferpos-to-filepos end 'approximate
+ 'utf-8-unix))
+ (cursor (clang-format--bufferpos-to-filepos (point) 'exact 'utf-8-unix))
+ (temp-buffer (generate-new-buffer " *clang-format-temp*"))
+ (temp-file (make-temp-file "clang-format"))
+ ;; Output is XML, which is always UTF-8. Input encoding should match
+ ;; the encoding used to convert between buffer and file positions,
+ ;; otherwise the offsets calculated above are off. For simplicity, we
+ ;; always use ‘utf-8-unix’ and ignore the buffer coding system.
+ (default-process-coding-system '(utf-8-unix . utf-8-unix)))
+ (unwind-protect
+ (let ((status (apply #'call-process-region
+ nil nil clang-format-executable
+ nil `(,temp-buffer ,temp-file) nil
+ `("-output-replacements-xml"
+ ;; Gaurd against a nil assume-file-name.
+ ;; If the clang-format option -assume-filename
+ ;; is given a blank string it will crash as per
+ ;; the following bug report
+ ;; https://bugs.llvm.org/show_bug.cgi?id=34667
+ ,@(and assume-file-name
+ (list "-assume-filename" assume-file-name))
+ "-style" ,style
+ "-offset" ,(number-to-string file-start)
+ "-length" ,(number-to-string (- file-end file-start))
+ "-cursor" ,(number-to-string cursor))))
+ (stderr (with-temp-buffer
+ (unless (zerop (cadr (insert-file-contents temp-file)))
+ (insert ": "))
+ (buffer-substring-no-properties
+ (point-min) (line-end-position)))))
+ (cond
+ ((stringp status)
+ (error "(clang-format killed by signal %s%s)" status stderr))
+ ((not (zerop status))
+ (error "(clang-format failed with code %d%s)" status stderr)))
+
+ (cl-destructuring-bind (replacements cursor incomplete-format)
+ (with-current-buffer temp-buffer
+ (clang-format--extract (car (xml-parse-region))))
+ (save-excursion
+ (dolist (rpl replacements)
+ (apply #'clang-format--replace rpl)))
+ (when cursor
+ (goto-char (clang-format--filepos-to-bufferpos cursor 'exact
+ 'utf-8-unix)))
+ (if incomplete-format
+ (message "(clang-format: incomplete (syntax errors)%s)" stderr)
+ (message "(clang-format: success%s)" stderr))))
+ (delete-file temp-file)
+ (when (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
+
+;;;###autoload
+(defun clang-format-buffer (&optional style assume-file-name)
+ "Use clang-format to format the current buffer according to STYLE.
+If no STYLE is given uses `clang-format-style'. Use ASSUME-FILE-NAME
+to locate a style config file. If no ASSUME-FILE-NAME is given uses
+the function `buffer-file-name'."
+ (interactive)
+ (clang-format-region (point-min) (point-max) style assume-file-name))
+
+;;;###autoload
+(defalias 'clang-format 'clang-format-region)
+
+(provide 'clang-format)
+;;; clang-format.el ends here
diff --git a/linux-x64/clang/share/clang/clang-format.py b/linux-x64/clang/share/clang/clang-format.py
new file mode 100755
index 0000000..5fe592a
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-format.py
@@ -0,0 +1,127 @@
+# This file is a minimal clang-format vim-integration. To install:
+# - Change 'binary' if clang-format is not on the path (see below).
+# - Add to your .vimrc:
+#
+# map <C-I> :pyf <path-to-this-file>/clang-format.py<cr>
+# imap <C-I> <c-o>:pyf <path-to-this-file>/clang-format.py<cr>
+#
+# The first line enables clang-format for NORMAL and VISUAL mode, the second
+# line adds support for INSERT mode. Change "C-I" to another binding if you
+# need clang-format on a different key (C-I stands for Ctrl+i).
+#
+# With this integration you can press the bound key and clang-format will
+# format the current line in NORMAL and INSERT mode or the selected region in
+# VISUAL mode. The line or region is extended to the next bigger syntactic
+# entity.
+#
+# You can also pass in the variable "l:lines" to choose the range for
+# formatting. This variable can either contain "<start line>:<end line>" or
+# "all" to format the full file. So, to format the full file, write a function
+# like:
+# :function FormatFile()
+# : let l:lines="all"
+# : pyf <path-to-this-file>/clang-format.py
+# :endfunction
+#
+# It operates on the current, potentially unsaved buffer and does not create
+# or save any files. To revert a formatting, just undo.
+from __future__ import print_function
+
+import difflib
+import json
+import platform
+import subprocess
+import sys
+import vim
+
+# set g:clang_format_path to the path to clang-format if it is not on the path
+# Change this to the full path if clang-format is not on the path.
+binary = 'clang-format'
+if vim.eval('exists("g:clang_format_path")') == "1":
+ binary = vim.eval('g:clang_format_path')
+
+# Change this to format according to other formatting styles. See the output of
+# 'clang-format --help' for a list of supported styles. The default looks for
+# a '.clang-format' or '_clang-format' file to indicate the style that should be
+# used.
+style = 'file'
+fallback_style = None
+if vim.eval('exists("g:clang_format_fallback_style")') == "1":
+ fallback_style = vim.eval('g:clang_format_fallback_style')
+
+def get_buffer(encoding):
+ if platform.python_version_tuple()[0] == '3':
+ return vim.current.buffer
+ return [ line.decode(encoding) for line in vim.current.buffer ]
+
+def main():
+ # Get the current text.
+ encoding = vim.eval("&encoding")
+ buf = get_buffer(encoding)
+ text = '\n'.join(buf)
+
+ # Determine range to format.
+ if vim.eval('exists("l:lines")') == '1':
+ lines = ['-lines', vim.eval('l:lines')]
+ elif vim.eval('exists("l:formatdiff")') == '1':
+ with open(vim.current.buffer.name, 'r') as f:
+ ondisk = f.read().splitlines();
+ sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)
+ lines = []
+ for op in reversed(sequence.get_opcodes()):
+ if op[0] not in ['equal', 'delete']:
+ lines += ['-lines', '%s:%s' % (op[3] + 1, op[4])]
+ if lines == []:
+ return
+ else:
+ lines = ['-lines', '%s:%s' % (vim.current.range.start + 1,
+ vim.current.range.end + 1)]
+
+ # Determine the cursor position.
+ cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2
+ if cursor < 0:
+ print('Couldn\'t determine cursor position. Is your file empty?')
+ return
+
+ # Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format.
+ startupinfo = None
+ if sys.platform.startswith('win32'):
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ startupinfo.wShowWindow = subprocess.SW_HIDE
+
+ # Call formatter.
+ command = [binary, '-style', style, '-cursor', str(cursor)]
+ if lines != ['-lines', 'all']:
+ command += lines
+ if fallback_style:
+ command.extend(['-fallback-style', fallback_style])
+ if vim.current.buffer.name:
+ command.extend(['-assume-filename', vim.current.buffer.name])
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE, startupinfo=startupinfo)
+ stdout, stderr = p.communicate(input=text.encode(encoding))
+
+ # If successful, replace buffer contents.
+ if stderr:
+ print(stderr)
+
+ if not stdout:
+ print(
+ 'No output from clang-format (crashed?).\n'
+ 'Please report to bugs.llvm.org.'
+ )
+ else:
+ lines = stdout.decode(encoding).split('\n')
+ output = json.loads(lines[0])
+ lines = lines[1:]
+ sequence = difflib.SequenceMatcher(None, buf, lines)
+ for op in reversed(sequence.get_opcodes()):
+ if op[0] is not 'equal':
+ vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
+ if output.get('IncompleteFormat'):
+ print('clang-format: incomplete (syntax errors)')
+ vim.command('goto %d' % (output['Cursor'] + 1))
+
+main()
diff --git a/linux-x64/clang/share/clang/clang-include-fixer.el b/linux-x64/clang/share/clang/clang-include-fixer.el
new file mode 100755
index 0000000..ab10002
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-include-fixer.el
@@ -0,0 +1,446 @@
+;;; clang-include-fixer.el --- Emacs integration of the clang include fixer -*- lexical-binding: t; -*-
+
+;; Keywords: tools, c
+;; Package-Requires: ((cl-lib "0.5") (json "1.2") (let-alist "1.0.4"))
+
+;;; Commentary:
+
+;; This package allows Emacs users to invoke the 'clang-include-fixer' within
+;; Emacs. 'clang-include-fixer' provides an automated way of adding #include
+;; directives for missing symbols in one translation unit, see
+;; <http://clang.llvm.org/extra/include-fixer.html>.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'json)
+(require 'let-alist)
+
+(defgroup clang-include-fixer nil
+ "Clang-based include fixer."
+ :group 'tools)
+
+(defvar clang-include-fixer-add-include-hook nil
+ "A hook that will be called for every added include.
+The first argument is the filename of the include, the second argument is
+non-nil if the include is a system-header.")
+
+(defcustom clang-include-fixer-executable
+ "clang-include-fixer"
+ "Location of the clang-include-fixer executable.
+
+A string containing the name or the full path of the executable."
+ :group 'clang-include-fixer
+ :type '(file :must-match t)
+ :risky t)
+
+(defcustom clang-include-fixer-input-format
+ 'yaml
+ "Input format for clang-include-fixer.
+This string is passed as -db argument to
+`clang-include-fixer-executable'."
+ :group 'clang-include-fixer
+ :type '(radio
+ (const :tag "Hard-coded mapping" :fixed)
+ (const :tag "YAML" yaml)
+ (symbol :tag "Other"))
+ :risky t)
+
+(defcustom clang-include-fixer-init-string
+ ""
+ "Database initialization string for clang-include-fixer.
+This string is passed as -input argument to
+`clang-include-fixer-executable'."
+ :group 'clang-include-fixer
+ :type 'string
+ :risky t)
+
+(defface clang-include-fixer-highlight '((t :background "green"))
+ "Used for highlighting the symbol for which a header file is being added.")
+
+;;;###autoload
+(defun clang-include-fixer ()
+ "Invoke the Include Fixer to insert missing C++ headers."
+ (interactive)
+ (message (concat "Calling the include fixer. "
+ "This might take some seconds. Please wait."))
+ (clang-include-fixer--start #'clang-include-fixer--add-header
+ "-output-headers"))
+
+;;;###autoload
+(defun clang-include-fixer-at-point ()
+ "Invoke the Clang include fixer for the symbol at point."
+ (interactive)
+ (let ((symbol (clang-include-fixer--symbol-at-point)))
+ (unless symbol
+ (user-error "No symbol at current location"))
+ (clang-include-fixer-from-symbol symbol)))
+
+;;;###autoload
+(defun clang-include-fixer-from-symbol (symbol)
+ "Invoke the Clang include fixer for the SYMBOL.
+When called interactively, prompts the user for a symbol."
+ (interactive
+ (list (read-string "Symbol: " (clang-include-fixer--symbol-at-point))))
+ (clang-include-fixer--start #'clang-include-fixer--add-header
+ (format "-query-symbol=%s" symbol)))
+
+(defun clang-include-fixer--start (callback &rest args)
+ "Asynchronously start clang-include-fixer with parameters ARGS.
+The current file name is passed after ARGS as last argument. If
+the call was successful the returned result is stored in a
+temporary buffer, and CALLBACK is called with the temporary
+buffer as only argument."
+ (unless buffer-file-name
+ (user-error "clang-include-fixer works only in buffers that visit a file"))
+ (let ((process (if (fboundp 'make-process)
+ ;; Prefer using ‘make-process’ if available, because
+ ;; ‘start-process’ doesn’t allow us to separate the
+ ;; standard error from the output.
+ (clang-include-fixer--make-process callback args)
+ (clang-include-fixer--start-process callback args))))
+ (save-restriction
+ (widen)
+ (process-send-region process (point-min) (point-max)))
+ (process-send-eof process))
+ nil)
+
+(defun clang-include-fixer--make-process (callback args)
+ "Start a new clang-incude-fixer process using `make-process'.
+CALLBACK is called after the process finishes successfully; it is
+called with a single argument, the buffer where standard output
+has been inserted. ARGS is a list of additional command line
+arguments. Return the new process object."
+ (let ((stdin (current-buffer))
+ (stdout (generate-new-buffer "*clang-include-fixer output*"))
+ (stderr (generate-new-buffer "*clang-include-fixer errors*")))
+ (make-process :name "clang-include-fixer"
+ :buffer stdout
+ :command (clang-include-fixer--command args)
+ :coding 'utf-8-unix
+ :noquery t
+ :connection-type 'pipe
+ :sentinel (clang-include-fixer--sentinel stdin stdout stderr
+ callback)
+ :stderr stderr)))
+
+(defun clang-include-fixer--start-process (callback args)
+ "Start a new clang-incude-fixer process using `start-process'.
+CALLBACK is called after the process finishes successfully; it is
+called with a single argument, the buffer where standard output
+has been inserted. ARGS is a list of additional command line
+arguments. Return the new process object."
+ (let* ((stdin (current-buffer))
+ (stdout (generate-new-buffer "*clang-include-fixer output*"))
+ (process-connection-type nil)
+ (process (apply #'start-process "clang-include-fixer" stdout
+ (clang-include-fixer--command args))))
+ (set-process-coding-system process 'utf-8-unix 'utf-8-unix)
+ (set-process-query-on-exit-flag process nil)
+ (set-process-sentinel process
+ (clang-include-fixer--sentinel stdin stdout nil
+ callback))
+ process))
+
+(defun clang-include-fixer--command (args)
+ "Return the clang-include-fixer command line.
+Returns a list; the first element is the binary to
+execute (`clang-include-fixer-executable'), and the remaining
+elements are the command line arguments. Adds proper arguments
+for `clang-include-fixer-input-format' and
+`clang-include-fixer-init-string'. Appends the current buffer's
+file name; prepends ARGS directly in front of it."
+ (cl-check-type args list)
+ `(,clang-include-fixer-executable
+ ,(format "-db=%s" clang-include-fixer-input-format)
+ ,(format "-input=%s" clang-include-fixer-init-string)
+ "-stdin"
+ ,@args
+ ,(buffer-file-name)))
+
+(defun clang-include-fixer--sentinel (stdin stdout stderr callback)
+ "Return a process sentinel for clang-include-fixer processes.
+STDIN, STDOUT, and STDERR are buffers for the standard streams;
+only STDERR may be nil. CALLBACK is called in the case of
+success; it is called with a single argument, STDOUT. On
+failure, a buffer containing the error output is displayed."
+ (cl-check-type stdin buffer-live)
+ (cl-check-type stdout buffer-live)
+ (cl-check-type stderr (or null buffer-live))
+ (cl-check-type callback function)
+ (lambda (process event)
+ (cl-check-type process process)
+ (cl-check-type event string)
+ (unwind-protect
+ (if (string-equal event "finished\n")
+ (progn
+ (when stderr (kill-buffer stderr))
+ (with-current-buffer stdin
+ (funcall callback stdout))
+ (kill-buffer stdout))
+ (when stderr (kill-buffer stdout))
+ (message "clang-include-fixer failed")
+ (with-current-buffer (or stderr stdout)
+ (insert "\nProcess " (process-name process)
+ ?\s event))
+ (display-buffer (or stderr stdout))))
+ nil))
+
+(defun clang-include-fixer--replace-buffer (stdout)
+ "Replace current buffer by content of STDOUT."
+ (cl-check-type stdout buffer-live)
+ (barf-if-buffer-read-only)
+ (cond ((fboundp 'replace-buffer-contents) (replace-buffer-contents stdout))
+ ((clang-include-fixer--insert-line stdout (current-buffer)))
+ (t (erase-buffer) (insert-buffer-substring stdout)))
+ (message "Fix applied")
+ nil)
+
+(defun clang-include-fixer--insert-line (from to)
+ "Insert a single missing line from the buffer FROM into TO.
+FROM and TO must be buffers. If the contents of FROM and TO are
+equal, do nothing and return non-nil. If FROM contains a single
+line missing from TO, insert that line into TO so that the buffer
+contents are equal and return non-nil. Otherwise, do nothing and
+return nil. Buffer restrictions are ignored."
+ (cl-check-type from buffer-live)
+ (cl-check-type to buffer-live)
+ (with-current-buffer from
+ (save-excursion
+ (save-restriction
+ (widen)
+ (with-current-buffer to
+ (save-excursion
+ (save-restriction
+ (widen)
+ ;; Search for the first buffer difference.
+ (let ((chars (abs (compare-buffer-substrings to nil nil from nil nil))))
+ (if (zerop chars)
+ ;; Buffer contents are equal, nothing to do.
+ t
+ (goto-char chars)
+ ;; We might have ended up in the middle of a line if the
+ ;; current line partially matches. In this case we would
+ ;; have to insert more than a line. Move to the beginning of
+ ;; the line to avoid this situation.
+ (beginning-of-line)
+ (with-current-buffer from
+ (goto-char chars)
+ (beginning-of-line)
+ (let ((from-begin (point))
+ (from-end (progn (forward-line) (point)))
+ (to-point (with-current-buffer to (point))))
+ ;; Search for another buffer difference after the line in
+ ;; question. If there is none, we can proceed.
+ (when (zerop (compare-buffer-substrings from from-end nil
+ to to-point nil))
+ (with-current-buffer to
+ (insert-buffer-substring from from-begin from-end))
+ t))))))))))))
+
+(defun clang-include-fixer--add-header (stdout)
+ "Analyse the result of include-fixer stored in STDOUT.
+Add a missing header if there is any. If there are multiple
+possible headers the user can select one of them to be included.
+Temporarily highlight the affected symbols. Asynchronously call
+clang-include-fixer to insert the selected header."
+ (cl-check-type stdout buffer-live)
+ (let ((context (clang-include-fixer--parse-json stdout)))
+ (let-alist context
+ (cond
+ ((null .QuerySymbolInfos)
+ (message "The file is fine, no need to add a header."))
+ ((null .HeaderInfos)
+ (message "Couldn't find header for '%s'"
+ (let-alist (car .QuerySymbolInfos) .RawIdentifier)))
+ (t
+ ;; Users may C-g in prompts, make sure the process sentinel
+ ;; behaves correctly.
+ (with-local-quit
+ ;; Replace the HeaderInfos list by a single header selected by
+ ;; the user.
+ (clang-include-fixer--select-header context)
+ ;; Call clang-include-fixer again to insert the selected header.
+ (clang-include-fixer--start
+ (let ((old-tick (buffer-chars-modified-tick)))
+ (lambda (stdout)
+ (when (/= old-tick (buffer-chars-modified-tick))
+ ;; Replacing the buffer now would undo the user’s changes.
+ (user-error (concat "The buffer has been changed "
+ "before the header could be inserted")))
+ (clang-include-fixer--replace-buffer stdout)
+ (let-alist context
+ (let-alist (car .HeaderInfos)
+ (with-local-quit
+ (run-hook-with-args 'clang-include-fixer-add-include-hook
+ (substring .Header 1 -1)
+ (string= (substring .Header 0 1) "<")))))))
+ (format "-insert-header=%s"
+ (clang-include-fixer--encode-json context))))))))
+ nil)
+
+(defun clang-include-fixer--select-header (context)
+ "Prompt the user for a header if necessary.
+CONTEXT must be a clang-include-fixer context object in
+association list format. If it contains more than one HeaderInfo
+element, prompt the user to select one of the headers. CONTEXT
+is modified to include only the selected element."
+ (cl-check-type context cons)
+ (let-alist context
+ (if (cdr .HeaderInfos)
+ (clang-include-fixer--prompt-for-header context)
+ (message "Only one include is missing: %s"
+ (let-alist (car .HeaderInfos) .Header))))
+ nil)
+
+(defvar clang-include-fixer--history nil
+ "History for `clang-include-fixer--prompt-for-header'.")
+
+(defun clang-include-fixer--prompt-for-header (context)
+ "Prompt the user for a single header.
+The choices are taken from the HeaderInfo elements in CONTEXT.
+They are replaced by the single element selected by the user."
+ (let-alist context
+ (let ((symbol (clang-include-fixer--symbol-name .QuerySymbolInfos))
+ ;; Add temporary highlighting so that the user knows which
+ ;; symbols the current session is about.
+ (overlays (remove nil
+ (mapcar #'clang-include-fixer--highlight .QuerySymbolInfos))))
+ (unwind-protect
+ (save-excursion
+ ;; While prompting, go to the closest overlay so that the user sees
+ ;; some context.
+ (when overlays
+ (goto-char (clang-include-fixer--closest-overlay overlays)))
+ (cl-flet ((header (info) (let-alist info .Header)))
+ ;; The header-infos is already sorted by include-fixer.
+ (let* ((header (completing-read
+ (clang-include-fixer--format-message
+ "Select include for '%s': " symbol)
+ (mapcar #'header .HeaderInfos)
+ nil :require-match nil
+ 'clang-include-fixer--history))
+ (info (cl-find header .HeaderInfos :key #'header :test #'string=)))
+ (cl-assert info)
+ (setcar .HeaderInfos info)
+ (setcdr .HeaderInfos nil))))
+ (mapc #'delete-overlay overlays)))))
+
+(defun clang-include-fixer--symbol-name (symbol-infos)
+ "Return the unique symbol name in SYMBOL-INFOS.
+Raise a signal if the symbol name is not unique."
+ (let ((symbols (delete-dups (mapcar (lambda (info)
+ (let-alist info .RawIdentifier))
+ symbol-infos))))
+ (when (cdr symbols)
+ (error "Multiple symbols %s returned" symbols))
+ (car symbols)))
+
+(defun clang-include-fixer--highlight (symbol-info)
+ "Add an overlay to highlight SYMBOL-INFO, if it points to a non-empty range.
+Return the overlay object, or nil."
+ (let-alist symbol-info
+ (unless (zerop .Range.Length)
+ (let ((overlay (make-overlay
+ (clang-include-fixer--filepos-to-bufferpos
+ .Range.Offset 'approximate)
+ (clang-include-fixer--filepos-to-bufferpos
+ (+ .Range.Offset .Range.Length) 'approximate))))
+ (overlay-put overlay 'face 'clang-include-fixer-highlight)
+ overlay))))
+
+(defun clang-include-fixer--closest-overlay (overlays)
+ "Return the start of the overlay in OVERLAYS that is closest to point."
+ (cl-check-type overlays cons)
+ (let ((point (point))
+ acc)
+ (dolist (overlay overlays acc)
+ (let ((start (overlay-start overlay)))
+ (when (or (null acc) (< (abs (- point start)) (abs (- point acc))))
+ (setq acc start))))))
+
+(defun clang-include-fixer--parse-json (buffer)
+ "Parse a JSON response from clang-include-fixer in BUFFER.
+Return the JSON object as an association list."
+ (with-current-buffer buffer
+ (save-excursion
+ (goto-char (point-min))
+ (let ((json-object-type 'alist)
+ (json-array-type 'list)
+ (json-key-type 'symbol)
+ (json-false :json-false)
+ (json-null nil)
+ (json-pre-element-read-function nil)
+ (json-post-element-read-function nil))
+ (json-read)))))
+
+(defun clang-include-fixer--encode-json (object)
+ "Return the JSON representation of OBJECT as a string."
+ (let ((json-encoding-separator ",")
+ (json-encoding-default-indentation " ")
+ (json-encoding-pretty-print nil)
+ (json-encoding-lisp-style-closings nil)
+ (json-encoding-object-sort-predicate nil))
+ (json-encode object)))
+
+(defun clang-include-fixer--symbol-at-point ()
+ "Return the qualified symbol at point.
+If there is no symbol at point, return nil."
+ ;; Let ‘bounds-of-thing-at-point’ to do the hard work and deal with edge
+ ;; cases.
+ (let ((bounds (bounds-of-thing-at-point 'symbol)))
+ (when bounds
+ (let ((beg (car bounds))
+ (end (cdr bounds)))
+ (save-excursion
+ ;; Extend the symbol range to the left. Skip over namespace
+ ;; delimiters and parent namespace names.
+ (goto-char beg)
+ (while (and (clang-include-fixer--skip-double-colon-backward)
+ (skip-syntax-backward "w_")))
+ ;; Skip over one more namespace delimiter, for absolute names.
+ (clang-include-fixer--skip-double-colon-backward)
+ (setq beg (point))
+ ;; Extend the symbol range to the right. Skip over namespace
+ ;; delimiters and child namespace names.
+ (goto-char end)
+ (while (and (clang-include-fixer--skip-double-colon-forward)
+ (skip-syntax-forward "w_")))
+ (setq end (point)))
+ (buffer-substring-no-properties beg end)))))
+
+(defun clang-include-fixer--skip-double-colon-forward ()
+ "Skip a double colon.
+When the next two characters are '::', skip them and return
+non-nil. Otherwise return nil."
+ (let ((end (+ (point) 2)))
+ (when (and (<= end (point-max))
+ (string-equal (buffer-substring-no-properties (point) end) "::"))
+ (goto-char end)
+ t)))
+
+(defun clang-include-fixer--skip-double-colon-backward ()
+ "Skip a double colon.
+When the previous two characters are '::', skip them and return
+non-nil. Otherwise return nil."
+ (let ((beg (- (point) 2)))
+ (when (and (>= beg (point-min))
+ (string-equal (buffer-substring-no-properties beg (point)) "::"))
+ (goto-char beg)
+ t)))
+
+;; ‘filepos-to-bufferpos’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-include-fixer--filepos-to-bufferpos
+ (if (fboundp 'filepos-to-bufferpos)
+ 'filepos-to-bufferpos
+ (lambda (byte &optional _quality _coding-system)
+ (byte-to-position (1+ byte)))))
+
+;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-include-fixer--format-message
+ (if (fboundp 'format-message) 'format-message 'format))
+
+(provide 'clang-include-fixer)
+;;; clang-include-fixer.el ends here
diff --git a/linux-x64/clang/share/clang/clang-include-fixer.py b/linux-x64/clang/share/clang/clang-include-fixer.py
new file mode 100755
index 0000000..0e9306d
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-include-fixer.py
@@ -0,0 +1,208 @@
+# This file is a minimal clang-include-fixer vim-integration. To install:
+# - Change 'binary' if clang-include-fixer is not on the path (see below).
+# - Add to your .vimrc:
+#
+# noremap <leader>cf :pyf path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/clang-include-fixer.py<cr>
+#
+# This enables clang-include-fixer for NORMAL and VISUAL mode. Change "<leader>cf"
+# to another binding if you need clang-include-fixer on a different key.
+#
+# To set up clang-include-fixer, see http://clang.llvm.org/extra/include-fixer.html
+#
+# With this integration you can press the bound key and clang-include-fixer will
+# be run on the current buffer.
+#
+# It operates on the current, potentially unsaved buffer and does not create
+# or save any files. To revert a fix, just undo.
+
+import argparse
+import difflib
+import json
+import re
+import subprocess
+import vim
+
+# set g:clang_include_fixer_path to the path to clang-include-fixer if it is not
+# on the path.
+# Change this to the full path if clang-include-fixer is not on the path.
+binary = 'clang-include-fixer'
+if vim.eval('exists("g:clang_include_fixer_path")') == "1":
+ binary = vim.eval('g:clang_include_fixer_path')
+
+maximum_suggested_headers = 3
+if vim.eval('exists("g:clang_include_fixer_maximum_suggested_headers")') == "1":
+ maximum_suggested_headers = max(
+ 1,
+ vim.eval('g:clang_include_fixer_maximum_suggested_headers'))
+
+increment_num = 5
+if vim.eval('exists("g:clang_include_fixer_increment_num")') == "1":
+ increment_num = max(
+ 1,
+ vim.eval('g:clang_include_fixer_increment_num'))
+
+jump_to_include = False
+if vim.eval('exists("g:clang_include_fixer_jump_to_include")') == "1":
+ jump_to_include = vim.eval('g:clang_include_fixer_jump_to_include') != "0"
+
+query_mode = False
+if vim.eval('exists("g:clang_include_fixer_query_mode")') == "1":
+ query_mode = vim.eval('g:clang_include_fixer_query_mode') != "0"
+
+
+def GetUserSelection(message, headers, maximum_suggested_headers):
+ eval_message = message + '\n'
+ for idx, header in enumerate(headers[0:maximum_suggested_headers]):
+ eval_message += "({0}). {1}\n".format(idx + 1, header)
+ eval_message += "Enter (q) to quit;"
+ if maximum_suggested_headers < len(headers):
+ eval_message += " (m) to show {0} more candidates.".format(
+ min(increment_num, len(headers) - maximum_suggested_headers))
+
+ eval_message += "\nSelect (default 1): "
+ res = vim.eval("input('{0}')".format(eval_message))
+ if res == '':
+ # choose the top ranked header by default
+ idx = 1
+ elif res == 'q':
+ raise Exception(' Insertion cancelled...')
+ elif res == 'm':
+ return GetUserSelection(message,
+ headers, maximum_suggested_headers + increment_num)
+ else:
+ try:
+ idx = int(res)
+ if idx <= 0 or idx > len(headers):
+ raise Exception()
+ except Exception:
+ # Show a new prompt on invalid option instead of aborting so that users
+ # don't need to wait for another include-fixer run.
+ print >> sys.stderr, "Invalid option:", res
+ return GetUserSelection(message, headers, maximum_suggested_headers)
+ return headers[idx - 1]
+
+
+def execute(command, text):
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ return p.communicate(input=text)
+
+
+def InsertHeaderToVimBuffer(header, text):
+ command = [binary, "-stdin", "-insert-header=" + json.dumps(header),
+ vim.current.buffer.name]
+ stdout, stderr = execute(command, text)
+ if stderr:
+ raise Exception(stderr)
+ if stdout:
+ lines = stdout.splitlines()
+ sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines)
+ line_num = None
+ for op in reversed(sequence.get_opcodes()):
+ if op[0] != 'equal':
+ vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
+ if op[0] == 'insert':
+ # line_num in vim is 1-based.
+ line_num = op[1] + 1
+
+ if jump_to_include and line_num:
+ vim.current.window.cursor = (line_num, 0)
+
+
+# The vim internal implementation (expand("cword"/"cWORD")) doesn't support
+# our use case very well, we re-implement our own one.
+def get_symbol_under_cursor():
+ line = vim.eval("line(\".\")")
+ # column number in vim is 1-based.
+ col = int(vim.eval("col(\".\")")) - 1
+ line_text = vim.eval("getline({0})".format(line))
+ if len(line_text) == 0: return ""
+ symbol_pos_begin = col
+ p = re.compile('[a-zA-Z0-9:_]')
+ while symbol_pos_begin >= 0 and p.match(line_text[symbol_pos_begin]):
+ symbol_pos_begin -= 1
+
+ symbol_pos_end = col
+ while symbol_pos_end < len(line_text) and p.match(line_text[symbol_pos_end]):
+ symbol_pos_end += 1
+ return line_text[symbol_pos_begin+1:symbol_pos_end]
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Vim integration for clang-include-fixer')
+ parser.add_argument('-db', default='yaml',
+ help='clang-include-fixer input format.')
+ parser.add_argument('-input', default='',
+ help='String to initialize the database.')
+ # Don't throw exception when parsing unknown arguements to make the script
+ # work in neovim.
+ # Neovim (at least v0.2.1) somehow mangles the sys.argv in a weird way: it
+ # will pass additional arguments (e.g. "-c script_host.py") to sys.argv,
+ # which makes the script fail.
+ args, _ = parser.parse_known_args()
+
+ # Get the current text.
+ buf = vim.current.buffer
+ text = '\n'.join(buf)
+
+ if query_mode:
+ symbol = get_symbol_under_cursor()
+ if len(symbol) == 0:
+ print "Skip querying empty symbol."
+ return
+ command = [binary, "-stdin", "-query-symbol="+get_symbol_under_cursor(),
+ "-db=" + args.db, "-input=" + args.input,
+ vim.current.buffer.name]
+ else:
+ # Run command to get all headers.
+ command = [binary, "-stdin", "-output-headers", "-db=" + args.db,
+ "-input=" + args.input, vim.current.buffer.name]
+ stdout, stderr = execute(command, text)
+ if stderr:
+ print >> sys.stderr, "Error while running clang-include-fixer: " + stderr
+ return
+
+ include_fixer_context = json.loads(stdout)
+ query_symbol_infos = include_fixer_context["QuerySymbolInfos"]
+ if not query_symbol_infos:
+ print "The file is fine, no need to add a header."
+ return
+ symbol = query_symbol_infos[0]["RawIdentifier"]
+ # The header_infos is already sorted by include-fixer.
+ header_infos = include_fixer_context["HeaderInfos"]
+ # Deduplicate headers while keeping the order, so that the same header would
+ # not be suggested twice.
+ unique_headers = []
+ seen = set()
+ for header_info in header_infos:
+ header = header_info["Header"]
+ if header not in seen:
+ seen.add(header)
+ unique_headers.append(header)
+
+ if not unique_headers:
+ print "Couldn't find a header for {0}.".format(symbol)
+ return
+
+ try:
+ selected = unique_headers[0]
+ inserted_header_infos = header_infos
+ if len(unique_headers) > 1:
+ selected = GetUserSelection(
+ "choose a header file for {0}.".format(symbol),
+ unique_headers, maximum_suggested_headers)
+ inserted_header_infos = [
+ header for header in header_infos if header["Header"] == selected]
+ include_fixer_context["HeaderInfos"] = inserted_header_infos
+
+ InsertHeaderToVimBuffer(include_fixer_context, text)
+ print "Added #include {0} for {1}.".format(selected, symbol)
+ except Exception as error:
+ print >> sys.stderr, error.message
+ return
+
+
+if __name__ == '__main__':
+ main()
diff --git a/linux-x64/clang/share/clang/clang-rename.el b/linux-x64/clang/share/clang/clang-rename.el
new file mode 100755
index 0000000..b6c3ed4
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-rename.el
@@ -0,0 +1,79 @@
+;;; clang-rename.el --- Renames every occurrence of a symbol found at <offset>. -*- lexical-binding: t; -*-
+
+;; Keywords: tools, c
+
+;;; Commentary:
+
+;; To install clang-rename.el make sure the directory of this file is in your
+;; `load-path' and add
+;;
+;; (require 'clang-rename)
+;;
+;; to your .emacs configuration.
+
+;;; Code:
+
+(defgroup clang-rename nil
+ "Integration with clang-rename"
+ :group 'c)
+
+(defcustom clang-rename-binary "clang-rename"
+ "Path to clang-rename executable."
+ :type '(file :must-match t)
+ :group 'clang-rename)
+
+;;;###autoload
+(defun clang-rename (new-name)
+ "Rename all instances of the symbol at point to NEW-NAME using clang-rename."
+ (interactive "sEnter a new name: ")
+ (save-some-buffers :all)
+ ;; clang-rename should not be combined with other operations when undoing.
+ (undo-boundary)
+ (let ((output-buffer (get-buffer-create "*clang-rename*")))
+ (with-current-buffer output-buffer (erase-buffer))
+ (let ((exit-code (call-process
+ clang-rename-binary nil output-buffer nil
+ (format "-offset=%d"
+ ;; clang-rename wants file (byte) offsets, not
+ ;; buffer (character) positions.
+ (clang-rename--bufferpos-to-filepos
+ ;; Emacs treats one character after a symbol as
+ ;; part of the symbol, but clang-rename doesn’t.
+ ;; Use the beginning of the current symbol, if
+ ;; available, to resolve the inconsistency.
+ (or (car (bounds-of-thing-at-point 'symbol))
+ (point))
+ 'exact))
+ (format "-new-name=%s" new-name)
+ "-i" (buffer-file-name))))
+ (if (and (integerp exit-code) (zerop exit-code))
+ ;; Success; revert current buffer so it gets the modifications.
+ (progn
+ (kill-buffer output-buffer)
+ (revert-buffer :ignore-auto :noconfirm :preserve-modes))
+ ;; Failure; append exit code to output buffer and display it.
+ (let ((message (clang-rename--format-message
+ "clang-rename failed with %s %s"
+ (if (integerp exit-code) "exit status" "signal")
+ exit-code)))
+ (with-current-buffer output-buffer
+ (insert ?\n message ?\n))
+ (message "%s" message)
+ (display-buffer output-buffer))))))
+
+(defalias 'clang-rename--bufferpos-to-filepos
+ (if (fboundp 'bufferpos-to-filepos)
+ 'bufferpos-to-filepos
+ ;; Emacs 24 doesn’t have ‘bufferpos-to-filepos’, simulate it using
+ ;; ‘position-bytes’.
+ (lambda (position &optional _quality _coding-system)
+ (1- (position-bytes position)))))
+
+;; ‘format-message’ is new in Emacs 25.1. Provide a fallback for older
+;; versions.
+(defalias 'clang-rename--format-message
+ (if (fboundp 'format-message) 'format-message 'format))
+
+(provide 'clang-rename)
+
+;;; clang-rename.el ends here
diff --git a/linux-x64/clang/share/clang/clang-rename.py b/linux-x64/clang/share/clang/clang-rename.py
new file mode 100755
index 0000000..3cc6644
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-rename.py
@@ -0,0 +1,61 @@
+'''
+Minimal clang-rename integration with Vim.
+
+Before installing make sure one of the following is satisfied:
+
+* clang-rename is in your PATH
+* `g:clang_rename_path` in ~/.vimrc points to valid clang-rename executable
+* `binary` in clang-rename.py points to valid to clang-rename executable
+
+To install, simply put this into your ~/.vimrc
+
+ noremap <leader>cr :pyf <path-to>/clang-rename.py<cr>
+
+IMPORTANT NOTE: Before running the tool, make sure you saved the file.
+
+All you have to do now is to place a cursor on a variable/function/class which
+you would like to rename and press '<leader>cr'. You will be prompted for a new
+name if the cursor points to a valid symbol.
+'''
+
+import vim
+import subprocess
+import sys
+
+def main():
+ binary = 'clang-rename'
+ if vim.eval('exists("g:clang_rename_path")') == "1":
+ binary = vim.eval('g:clang_rename_path')
+
+ # Get arguments for clang-rename binary.
+ offset = int(vim.eval('line2byte(line("."))+col(".")')) - 2
+ if offset < 0:
+ print >> sys.stderr, '''Couldn\'t determine cursor position.
+ Is your file empty?'''
+ return
+ filename = vim.current.buffer.name
+
+ new_name_request_message = 'type new name:'
+ new_name = vim.eval("input('{}\n')".format(new_name_request_message))
+
+ # Call clang-rename.
+ command = [binary,
+ filename,
+ '-i',
+ '-offset', str(offset),
+ '-new-name', str(new_name)]
+ # FIXME: make it possible to run the tool on unsaved file.
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+
+ if stderr:
+ print stderr
+
+ # Reload all buffers in Vim.
+ vim.command("checktime")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/linux-x64/clang/share/clang/clang-tidy-diff.py b/linux-x64/clang/share/clang/clang-tidy-diff.py
new file mode 100755
index 0000000..f2c15e5
--- /dev/null
+++ b/linux-x64/clang/share/clang/clang-tidy-diff.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+#
+#===- clang-tidy-diff.py - ClangTidy Diff Checker ------------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+ClangTidy Diff Checker
+======================
+
+This script reads input from a unified diff, runs clang-tidy on all changed
+files and outputs clang-tidy warnings in changed lines only. This is useful to
+detect clang-tidy regressions in the lines touched by a specific patch.
+Example usage for git/svn users:
+
+ git diff -U0 HEAD^ | clang-tidy-diff.py -p1
+ svn diff --diff-cmd=diff -x-U0 | \
+ clang-tidy-diff.py -fix -checks=-*,modernize-use-override
+
+"""
+
+import argparse
+import json
+import re
+import subprocess
+import sys
+
+
+def main():
+ parser = argparse.ArgumentParser(description=
+ 'Run clang-tidy against changed files, and '
+ 'output diagnostics only for modified '
+ 'lines.')
+ parser.add_argument('-clang-tidy-binary', metavar='PATH',
+ default='clang-tidy',
+ help='path to clang-tidy binary')
+ parser.add_argument('-p', metavar='NUM', default=0,
+ help='strip the smallest prefix containing P slashes')
+ parser.add_argument('-regex', metavar='PATTERN', default=None,
+ help='custom pattern selecting file paths to check '
+ '(case sensitive, overrides -iregex)')
+ parser.add_argument('-iregex', metavar='PATTERN', default=
+ r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc)',
+ help='custom pattern selecting file paths to check '
+ '(case insensitive, overridden by -regex)')
+
+ parser.add_argument('-fix', action='store_true', default=False,
+ help='apply suggested fixes')
+ parser.add_argument('-checks',
+ help='checks filter, when not specified, use clang-tidy '
+ 'default',
+ default='')
+ parser.add_argument('-path', dest='build_path',
+ help='Path used to read a compile command database.')
+ parser.add_argument('-extra-arg', dest='extra_arg',
+ action='append', default=[],
+ help='Additional argument to append to the compiler '
+ 'command line.')
+ parser.add_argument('-extra-arg-before', dest='extra_arg_before',
+ action='append', default=[],
+ help='Additional argument to prepend to the compiler '
+ 'command line.')
+ parser.add_argument('-quiet', action='store_true', default=False,
+ help='Run clang-tidy in quiet mode')
+ clang_tidy_args = []
+ argv = sys.argv[1:]
+ if '--' in argv:
+ clang_tidy_args.extend(argv[argv.index('--'):])
+ argv = argv[:argv.index('--')]
+
+ args = parser.parse_args(argv)
+
+ # Extract changed lines for each file.
+ filename = None
+ lines_by_file = {}
+ for line in sys.stdin:
+ match = re.search('^\+\+\+\ \"?(.*?/){%s}([^ \t\n\"]*)' % args.p, line)
+ if match:
+ filename = match.group(2)
+ if filename == None:
+ continue
+
+ if args.regex is not None:
+ if not re.match('^%s$' % args.regex, filename):
+ continue
+ else:
+ if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
+ continue
+
+ match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
+ if match:
+ start_line = int(match.group(1))
+ line_count = 1
+ if match.group(3):
+ line_count = int(match.group(3))
+ if line_count == 0:
+ continue
+ end_line = start_line + line_count - 1;
+ lines_by_file.setdefault(filename, []).append([start_line, end_line])
+
+ if len(lines_by_file) == 0:
+ print("No relevant changes found.")
+ sys.exit(0)
+
+ line_filter_json = json.dumps(
+ [{"name" : name, "lines" : lines_by_file[name]} for name in lines_by_file],
+ separators = (',', ':'))
+
+ quote = "";
+ if sys.platform == 'win32':
+ line_filter_json=re.sub(r'"', r'"""', line_filter_json)
+ else:
+ quote = "'";
+
+ # Run clang-tidy on files containing changes.
+ command = [args.clang_tidy_binary]
+ command.append('-line-filter=' + quote + line_filter_json + quote)
+ if args.fix:
+ command.append('-fix')
+ if args.checks != '':
+ command.append('-checks=' + quote + args.checks + quote)
+ if args.quiet:
+ command.append('-quiet')
+ if args.build_path is not None:
+ command.append('-p=%s' % args.build_path)
+ command.extend(lines_by_file.keys())
+ for arg in args.extra_arg:
+ command.append('-extra-arg=%s' % arg)
+ for arg in args.extra_arg_before:
+ command.append('-extra-arg-before=%s' % arg)
+ command.extend(clang_tidy_args)
+
+ sys.exit(subprocess.call(' '.join(command), shell=True))
+
+if __name__ == '__main__':
+ main()
diff --git a/linux-x64/clang/share/clang/run-clang-tidy.py b/linux-x64/clang/share/clang/run-clang-tidy.py
new file mode 100755
index 0000000..ce46c0e
--- /dev/null
+++ b/linux-x64/clang/share/clang/run-clang-tidy.py
@@ -0,0 +1,313 @@
+#!/usr/bin/env python
+#
+#===- run-clang-tidy.py - Parallel clang-tidy runner ---------*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+# FIXME: Integrate with clang-tidy-diff.py
+
+"""
+Parallel clang-tidy runner
+==========================
+
+Runs clang-tidy over all files in a compilation database. Requires clang-tidy
+and clang-apply-replacements in $PATH.
+
+Example invocations.
+- Run clang-tidy on all files in the current working directory with a default
+ set of checks and show warnings in the cpp files and all project headers.
+ run-clang-tidy.py $PWD
+
+- Fix all header guards.
+ run-clang-tidy.py -fix -checks=-*,llvm-header-guard
+
+- Fix all header guards included from clang-tidy and header guards
+ for clang-tidy headers.
+ run-clang-tidy.py -fix -checks=-*,llvm-header-guard extra/clang-tidy \
+ -header-filter=extra/clang-tidy
+
+Compilation database setup:
+http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+"""
+
+from __future__ import print_function
+
+import argparse
+import glob
+import json
+import multiprocessing
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+import traceback
+import yaml
+
+is_py2 = sys.version[0] == '2'
+
+if is_py2:
+ import Queue as queue
+else:
+ import queue as queue
+
+def find_compilation_database(path):
+ """Adjusts the directory until a compilation database is found."""
+ result = './'
+ while not os.path.isfile(os.path.join(result, path)):
+ if os.path.realpath(result) == '/':
+ print('Error: could not find compilation database.')
+ sys.exit(1)
+ result += '../'
+ return os.path.realpath(result)
+
+
+def make_absolute(f, directory):
+ if os.path.isabs(f):
+ return f
+ return os.path.normpath(os.path.join(directory, f))
+
+
+def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
+ header_filter, extra_arg, extra_arg_before, quiet,
+ config):
+ """Gets a command line for clang-tidy."""
+ start = [clang_tidy_binary]
+ if header_filter is not None:
+ start.append('-header-filter=' + header_filter)
+ else:
+ # Show warnings in all in-project headers by default.
+ start.append('-header-filter=^' + build_path + '/.*')
+ if checks:
+ start.append('-checks=' + checks)
+ if tmpdir is not None:
+ start.append('-export-fixes')
+ # Get a temporary file. We immediately close the handle so clang-tidy can
+ # overwrite it.
+ (handle, name) = tempfile.mkstemp(suffix='.yaml', dir=tmpdir)
+ os.close(handle)
+ start.append(name)
+ for arg in extra_arg:
+ start.append('-extra-arg=%s' % arg)
+ for arg in extra_arg_before:
+ start.append('-extra-arg-before=%s' % arg)
+ start.append('-p=' + build_path)
+ if quiet:
+ start.append('-quiet')
+ if config:
+ start.append('-config=' + config)
+ start.append(f)
+ return start
+
+
+def merge_replacement_files(tmpdir, mergefile):
+ """Merge all replacement files in a directory into a single file"""
+ # The fixes suggested by clang-tidy >= 4.0.0 are given under
+ # the top level key 'Diagnostics' in the output yaml files
+ mergekey="Diagnostics"
+ merged=[]
+ for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')):
+ content = yaml.safe_load(open(replacefile, 'r'))
+ if not content:
+ continue # Skip empty files.
+ merged.extend(content.get(mergekey, []))
+
+ if merged:
+ # MainSourceFile: The key is required by the definition inside
+ # include/clang/Tooling/ReplacementsYaml.h, but the value
+ # is actually never used inside clang-apply-replacements,
+ # so we set it to '' here.
+ output = { 'MainSourceFile': '', mergekey: merged }
+ with open(mergefile, 'w') as out:
+ yaml.safe_dump(output, out)
+ else:
+ # Empty the file:
+ open(mergefile, 'w').close()
+
+
+def check_clang_apply_replacements_binary(args):
+ """Checks if invoking supplied clang-apply-replacements binary works."""
+ try:
+ subprocess.check_call([args.clang_apply_replacements_binary, '--version'])
+ except:
+ print('Unable to run clang-apply-replacements. Is clang-apply-replacements '
+ 'binary correctly specified?', file=sys.stderr)
+ traceback.print_exc()
+ sys.exit(1)
+
+
+def apply_fixes(args, tmpdir):
+ """Calls clang-apply-fixes on a given directory."""
+ invocation = [args.clang_apply_replacements_binary]
+ if args.format:
+ invocation.append('-format')
+ if args.style:
+ invocation.append('-style=' + args.style)
+ invocation.append(tmpdir)
+ subprocess.call(invocation)
+
+
+def run_tidy(args, tmpdir, build_path, queue, failed_files):
+ """Takes filenames out of queue and runs clang-tidy on them."""
+ while True:
+ name = queue.get()
+ invocation = get_tidy_invocation(name, args.clang_tidy_binary, args.checks,
+ tmpdir, build_path, args.header_filter,
+ args.extra_arg, args.extra_arg_before,
+ args.quiet, args.config)
+ sys.stdout.write(' '.join(invocation) + '\n')
+ return_code = subprocess.call(invocation)
+ if return_code != 0:
+ failed_files.append(name)
+ queue.task_done()
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Runs clang-tidy over all files '
+ 'in a compilation database. Requires '
+ 'clang-tidy and clang-apply-replacements in '
+ '$PATH.')
+ parser.add_argument('-clang-tidy-binary', metavar='PATH',
+ default='clang-tidy',
+ help='path to clang-tidy binary')
+ parser.add_argument('-clang-apply-replacements-binary', metavar='PATH',
+ default='clang-apply-replacements',
+ help='path to clang-apply-replacements binary')
+ parser.add_argument('-checks', default=None,
+ help='checks filter, when not specified, use clang-tidy '
+ 'default')
+ parser.add_argument('-config', default=None,
+ help='Specifies a configuration in YAML/JSON format: '
+ ' -config="{Checks: \'*\', '
+ ' CheckOptions: [{key: x, '
+ ' value: y}]}" '
+ 'When the value is empty, clang-tidy will '
+ 'attempt to find a file named .clang-tidy for '
+ 'each source file in its parent directories.')
+ parser.add_argument('-header-filter', default=None,
+ help='regular expression matching the names of the '
+ 'headers to output diagnostics from. Diagnostics from '
+ 'the main file of each translation unit are always '
+ 'displayed.')
+ parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes',
+ help='Create a yaml file to store suggested fixes in, '
+ 'which can be applied with clang-apply-replacements.')
+ parser.add_argument('-j', type=int, default=0,
+ help='number of tidy instances to be run in parallel.')
+ parser.add_argument('files', nargs='*', default=['.*'],
+ help='files to be processed (regex on path)')
+ parser.add_argument('-fix', action='store_true', help='apply fix-its')
+ parser.add_argument('-format', action='store_true', help='Reformat code '
+ 'after applying fixes')
+ parser.add_argument('-style', default='file', help='The style of reformat '
+ 'code after applying fixes')
+ parser.add_argument('-p', dest='build_path',
+ help='Path used to read a compile command database.')
+ parser.add_argument('-extra-arg', dest='extra_arg',
+ action='append', default=[],
+ help='Additional argument to append to the compiler '
+ 'command line.')
+ parser.add_argument('-extra-arg-before', dest='extra_arg_before',
+ action='append', default=[],
+ help='Additional argument to prepend to the compiler '
+ 'command line.')
+ parser.add_argument('-quiet', action='store_true',
+ help='Run clang-tidy in quiet mode')
+ args = parser.parse_args()
+
+ db_path = 'compile_commands.json'
+
+ if args.build_path is not None:
+ build_path = args.build_path
+ else:
+ # Find our database
+ build_path = find_compilation_database(db_path)
+
+ try:
+ invocation = [args.clang_tidy_binary, '-list-checks']
+ invocation.append('-p=' + build_path)
+ if args.checks:
+ invocation.append('-checks=' + args.checks)
+ invocation.append('-')
+ subprocess.check_call(invocation)
+ except:
+ print("Unable to run clang-tidy.", file=sys.stderr)
+ sys.exit(1)
+
+ # Load the database and extract all files.
+ database = json.load(open(os.path.join(build_path, db_path)))
+ files = [make_absolute(entry['file'], entry['directory'])
+ for entry in database]
+
+ max_task = args.j
+ if max_task == 0:
+ max_task = multiprocessing.cpu_count()
+
+ tmpdir = None
+ if args.fix or args.export_fixes:
+ check_clang_apply_replacements_binary(args)
+ tmpdir = tempfile.mkdtemp()
+
+ # Build up a big regexy filter from all command line arguments.
+ file_name_re = re.compile('|'.join(args.files))
+
+ return_code = 0
+ try:
+ # Spin up a bunch of tidy-launching threads.
+ task_queue = queue.Queue(max_task)
+ # List of files with a non-zero return code.
+ failed_files = []
+ for _ in range(max_task):
+ t = threading.Thread(target=run_tidy,
+ args=(args, tmpdir, build_path, task_queue, failed_files))
+ t.daemon = True
+ t.start()
+
+ # Fill the queue with files.
+ for name in files:
+ if file_name_re.search(name):
+ task_queue.put(name)
+
+ # Wait for all threads to be done.
+ task_queue.join()
+ if len(failed_files):
+ return_code = 1
+
+ except KeyboardInterrupt:
+ # This is a sad hack. Unfortunately subprocess goes
+ # bonkers with ctrl-c and we start forking merrily.
+ print('\nCtrl-C detected, goodbye.')
+ if tmpdir:
+ shutil.rmtree(tmpdir)
+ os.kill(0, 9)
+
+ if args.export_fixes:
+ print('Writing fixes to ' + args.export_fixes + ' ...')
+ try:
+ merge_replacement_files(tmpdir, args.export_fixes)
+ except:
+ print('Error exporting fixes.\n', file=sys.stderr)
+ traceback.print_exc()
+ return_code=1
+
+ if args.fix:
+ print('Applying fixes ...')
+ try:
+ apply_fixes(args, tmpdir)
+ except:
+ print('Error applying fixes.\n', file=sys.stderr)
+ traceback.print_exc()
+ return_code=1
+
+ if tmpdir:
+ shutil.rmtree(tmpdir)
+ sys.exit(return_code)
+
+if __name__ == '__main__':
+ main()
diff --git a/linux-x64/clang/share/clang/run-find-all-symbols.py b/linux-x64/clang/share/clang/run-find-all-symbols.py
new file mode 100755
index 0000000..461d959
--- /dev/null
+++ b/linux-x64/clang/share/clang/run-find-all-symbols.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#
+#=- run-find-all-symbols.py - Parallel find-all-symbols runner -*- python -*-=#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+"""
+Parallel find-all-symbols runner
+================================
+
+Runs find-all-symbols over all files in a compilation database.
+
+Example invocations.
+- Run find-all-symbols on all files in the current working directory.
+ run-find-all-symbols.py <source-file>
+
+Compilation database setup:
+http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
+"""
+
+import argparse
+import json
+import multiprocessing
+import os
+import Queue
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+
+
+def find_compilation_database(path):
+ """Adjusts the directory until a compilation database is found."""
+ result = './'
+ while not os.path.isfile(os.path.join(result, path)):
+ if os.path.realpath(result) == '/':
+ print 'Error: could not find compilation database.'
+ sys.exit(1)
+ result += '../'
+ return os.path.realpath(result)
+
+
+def MergeSymbols(directory, args):
+ """Merge all symbol files (yaml) in a given directaory into a single file."""
+ invocation = [args.binary, '-merge-dir='+directory, args.saving_path]
+ subprocess.call(invocation)
+ print 'Merge is finished. Saving results in ' + args.saving_path
+
+
+def run_find_all_symbols(args, tmpdir, build_path, queue):
+ """Takes filenames out of queue and runs find-all-symbols on them."""
+ while True:
+ name = queue.get()
+ invocation = [args.binary, name, '-output-dir='+tmpdir, '-p='+build_path]
+ sys.stdout.write(' '.join(invocation) + '\n')
+ subprocess.call(invocation)
+ queue.task_done()
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Runs find-all-symbols over all'
+ 'files in a compilation database.')
+ parser.add_argument('-binary', metavar='PATH',
+ default='./bin/find-all-symbols',
+ help='path to find-all-symbols binary')
+ parser.add_argument('-j', type=int, default=0,
+ help='number of instances to be run in parallel.')
+ parser.add_argument('-p', dest='build_path',
+ help='path used to read a compilation database.')
+ parser.add_argument('-saving-path', default='./find_all_symbols_db.yaml',
+ help='result saving path')
+ args = parser.parse_args()
+
+ db_path = 'compile_commands.json'
+
+ if args.build_path is not None:
+ build_path = args.build_path
+ else:
+ build_path = find_compilation_database(db_path)
+
+ tmpdir = tempfile.mkdtemp()
+
+ # Load the database and extract all files.
+ database = json.load(open(os.path.join(build_path, db_path)))
+ files = [entry['file'] for entry in database]
+
+ max_task = args.j
+ if max_task == 0:
+ max_task = multiprocessing.cpu_count()
+
+ try:
+ # Spin up a bunch of tidy-launching threads.
+ queue = Queue.Queue(max_task)
+ for _ in range(max_task):
+ t = threading.Thread(target=run_find_all_symbols,
+ args=(args, tmpdir, build_path, queue))
+ t.daemon = True
+ t.start()
+
+ # Fill the queue with files.
+ for name in files:
+ queue.put(name)
+
+ # Wait for all threads to be done.
+ queue.join()
+
+ MergeSymbols(tmpdir, args)
+
+
+ except KeyboardInterrupt:
+ # This is a sad hack. Unfortunately subprocess goes
+ # bonkers with ctrl-c and we start forking merrily.
+ print '\nCtrl-C detected, goodbye.'
+ os.kill(0, 9)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/linux-x64/clang/share/man/man1/scan-build.1 b/linux-x64/clang/share/man/man1/scan-build.1
new file mode 100755
index 0000000..3d3a9f8
--- /dev/null
+++ b/linux-x64/clang/share/man/man1/scan-build.1
@@ -0,0 +1,349 @@
+.\" This file is distributed under the University of Illinois Open Source
+.\" License. See LICENSE.TXT for details.
+.\" $Id$
+.Dd May 25, 2012
+.Dt SCAN-BUILD 1
+.Os "clang" "3.5"
+.Sh NAME
+.Nm scan-build
+.Nd Clang static analyzer
+.Sh SYNOPSIS
+.Nm
+.Op Fl ohkvV
+.Op Fl analyze-headers
+.Op Fl enable-checker Op Ar checker_name
+.Op Fl disable-checker Op Ar checker_name
+.Op Fl Fl help
+.Op Fl Fl help-checkers
+.Op Fl Fl html-title Op Ar =title
+.Op Fl Fl keep-going
+.Op Fl plist
+.Op Fl plist-html
+.Op Fl Fl status-bugs
+.Op Fl Fl use-c++ Op Ar =compiler_path
+.Op Fl Fl use-cc Op Ar =compiler_path
+.Op Fl Fl view
+.Op Fl constraints Op Ar model
+.Op Fl maxloop Ar N
+.Op Fl no-failure-reports
+.Op Fl stats
+.Op Fl store Op Ar model
+.Ar build_command
+.Op build_options
+.\"
+.\" Sh DESCRIPTION
+.Sh DESCRIPTION
+.Nm
+is a Perl script that invokes the Clang static analyzer. Options used by
+.Nm
+or by the analyzer appear first, followed by the
+.Ar build_command
+and any
+.Ar build_options
+normally used to build the target system.
+.Pp
+The static analyzer employs a long list of checking algorithms, see
+.Sx CHECKERS .
+Output can be written in standard
+.Li .plist
+and/or HTML format.
+.Pp
+The following options are supported:
+.Bl -tag -width indent
+.It Fl analyze-headers
+Also analyze functions in #included files.
+.It Fl enable-checker Ar checker_name , Fl disable-checker Ar checker_name
+Enable/disable
+.Ar checker_name .
+See
+.Sx CHECKERS .
+.It Fl h , Fl Fl help
+Display this message.
+.It Fl Fl help-checkers
+List default checkers, see
+.Sx CHECKERS .
+.It Fl Fl html-title Ns Op = Ns Ar title
+Specify the title used on generated HTML pages.
+A default title is generated if
+.Ar title
+is not specified.
+.It Fl k , Fl Fl keep-going
+Add a
+.Dq keep on going
+option to
+.Ar build_command .
+Currently supports make and xcodebuild. This is a convenience option;
+one can specify this behavior directly using build options.
+.It Fl o
+Target directory for HTML report files. Subdirectories will be
+created as needed to represent separate invocations
+of the analyzer. If this option is not specified, a directory is
+created in /tmp (TMPDIR on Mac OS X) to store the reports.
+.It Fl plist
+Output the results as a set of
+.Li .plist
+files. (By default the output of
+.Nm
+is a set of HTML files.)
+.It Fl plist-html
+Output the results as a set of HTML and .plist files
+.It Fl Fl status-bugs
+Set exit status to 1 if it found potential bugs and 0 otherwise. By
+default the exit status of
+.Nm
+is that returned by
+.Ar build_command .
+.It Fl Fl use-c++ Ns Op = Ns Ar compiler_path
+Guess the default compiler for your C++ and Objective-C++ code. Use this
+option to specify an alternate compiler.
+.It Fl Fl use-cc Ns Op = Ns Ar compiler_path
+Guess the default compiler for your C and Objective-C code. Use this
+option to specify an alternate compiler.
+.It Fl v
+Verbose output from
+.Nm
+and the analyzer. A second and
+third
+.Ar v
+increases verbosity.
+.It Fl V , Fl Fl view
+View analysis results in a web browser when the build completes.
+.It Fl constraints Op Ar model
+Specify the contraint engine used by the analyzer. By default the
+.Ql range
+model is used. Specifying
+.Ql basic
+uses a simpler, less powerful constraint model used by checker-0.160
+and earlier.
+.It Fl maxloop Ar N
+Specifiy the number of times a block can be visited before giving
+up. Default is 4. Increase for more comprehensive coverage at a
+cost of speed.
+.It Fl no-failure-reports
+Do not create a
+.Ql failures
+subdirectory that includes analyzer crash reports and preprocessed
+source files.
+.It Fl stats
+Generates visitation statistics for the project being analyzed.
+.It Fl store Op Ar model
+Specify the store model used by the analyzer. By default, the
+.Ql region
+store model is used.
+.Ql region
+specifies a field-
+sensitive store model. Users can also specify
+.Ql basic
+which is far less precise but can more quickly analyze code.
+.Ql basic
+was the default store model for checker-0.221 and earlier.
+.\"
+.El
+.Sh EXIT STATUS
+.Nm
+returns the value returned by
+.Ar build_command
+unless
+.Fl Fl status-bugs
+or
+.Fl Fl keep-going
+is used.
+.\"
+.\" Other sections not yet used ...
+.\" .Sh ENVIRONMENT
+.\" .Sh FILES
+.\" .Sh DIAGNOSTICS
+.\" .Sh COMPATIBILITY
+.\" .Sh HISTORY
+.\" .Sh BUGS
+.\"
+.Sh CHECKERS
+The checkers listed below may be enabled/disabled using the
+.Fl enable-checker
+and
+.Fl disable-checker
+options.
+A default group of checkers is run unless explicitly disabled.
+Exactly which checkers constitute the default group is a function
+of the operating system in use; they are listed with
+.Fl Fl help-checkers .
+.Bl -tag -width indent.
+.It core.AdjustedReturnValue
+Check to see if the return value of a function call is different than
+the caller expects (e.g., from calls through function pointers).
+.It core.AttributeNonNull
+Check for null pointers passed as arguments to a function whose arguments are marked with the
+.Ql nonnull
+attribute.
+.It core.CallAndMessage
+Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers).
+.It core.DivideZero
+Check for division by zero.
+.It core.NullDereference
+Check for dereferences of null pointers.
+.It core.StackAddressEscape
+Check that addresses to stack memory do not escape the function.
+.It core.UndefinedBinaryOperatorResult
+Check for undefined results of binary operators.
+.It core.VLASize
+Check for declarations of VLA of undefined or zero size.
+.It core.builtin.BuiltinFunctions
+Evaluate compiler builtin functions, e.g.
+.Fn alloca .
+.It core.builtin.NoReturnFunctions
+Evaluate
+.Ql panic
+functions that are known to not return to the caller.
+.It core.uninitialized.ArraySubscript
+Check for uninitialized values used as array subscripts.
+.It core.uninitialized.Assign
+Check for assigning uninitialized values.
+.It core.uninitialized.Branch
+Check for uninitialized values used as branch conditions.
+.It core.uninitialized.CapturedBlockVariable
+Check for blocks that capture uninitialized values.
+.It core.uninitialized.UndefReturn
+Check for uninitialized values being returned to the caller.
+.It deadcode.DeadStores
+Check for values stored to variables that are never read afterwards.
+.It debug.DumpCFG
+Display Control-Flow Graphs.
+.It debug.DumpCallGraph
+Display Call Graph.
+.It debug.DumpDominators
+Print the dominance tree for a given Control-Flow Graph.
+.It debug.DumpLiveVars
+Print results of live variable analysis.
+.It debug.Stats
+Emit warnings with analyzer statistics.
+.It debug.TaintTest
+Mark tainted symbols as such.
+.It debug.ViewCFG
+View Control-Flow Graphs using
+.Ic GraphViz .
+.It debug.ViewCallGraph
+View Call Graph using
+.Ic GraphViz .
+.It llvm.Conventions
+Check code for LLVM codebase conventions.
+.It osx.API
+Check for proper uses of various Mac OS X APIs.
+.It osx.AtomicCAS
+Evaluate calls to
+.Vt OSAtomic
+functions.
+.It osx.SecKeychainAPI
+Check for proper uses of Secure Keychain APIs.
+.It osx.cocoa.AtSync
+Check for null pointers used as mutexes for @synchronized.
+.It osx.cocoa.ClassRelease
+Check for sending
+.Ql retain ,
+.Ql release,
+or
+.Ql autorelease
+directly to a Class.
+.It osx.cocoa.IncompatibleMethodTypes
+Warn about Objective-C method signatures with type incompatibilities.
+.It osx.cocoa.NSAutoreleasePool
+Warn for suboptimal uses of
+.Vt NSAutoreleasePool
+in Objective-C GC mode.
+.It osx.cocoa.NSError
+Check usage of NSError** parameters.
+.It osx.cocoa.NilArg
+Check for prohibited nil arguments to Objective-C method calls.
+.It osx.cocoa.RetainCount
+Check for leaks and improper reference count management.
+.It osx.cocoa.SelfInit
+Check that
+.Ql self
+is properly initialized inside an initializer method.
+.It osx.cocoa.UnusedIvars
+Warn about private ivars that are never used.
+.It osx.cocoa.VariadicMethodTypes
+Check for passing non-Objective-C types to variadic methods that expect only Objective-C types.
+.It osx.coreFoundation.CFError
+Check usage of CFErrorRef* parameters.
+.It osx.coreFoundation.CFNumber
+Check for proper uses of
+.Fn CFNumberCreate .
+.It osx.coreFoundation.CFRetainRelease
+Check for null arguments to
+.Fn CFRetain ,
+.Fn CFRelease ,
+and
+.Fn CFMakeCollectable .
+.It osx.coreFoundation.containers.OutOfBounds
+Checks for index out-of-bounds when using the
+.Vt CFArray
+API.
+.It osx.coreFoundation.containers.PointerSizedValues
+Warns if
+.Vt CFArray ,
+.Vt CFDictionary ,
+or
+.Vt CFSet
+are created with non-pointer-size values.
+.It security.FloatLoopCounter
+Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP).
+.It security.insecureAPI.UncheckedReturn
+Warn on uses of functions whose return values must be always checked.
+.It security.insecureAPI.getpw
+Warn on uses of
+.Fn getpw .
+.It security.insecureAPI.gets
+Warn on uses of
+.Fn gets .
+.It security.insecureAPI.mkstemp
+Warn when
+.Fn mkstemp
+is passed fewer than 6 X's in the format string.
+.It security.insecureAPI.mktemp
+Warn on uses of
+.Fn mktemp .
+.It security.insecureAPI.rand
+Warn on uses of
+.Fn rand ,
+.Fn random ,
+and related functions.
+.It security.insecureAPI.strcpy
+Warn on uses of
+.Fn strcpy
+and
+.Fn strcat .
+.It security.insecureAPI.vfork
+Warn on uses of
+.Fn vfork .
+.It unix.API
+Check calls to various UNIX/Posix functions.
+.It unix.Malloc
+Check for memory leaks, double free, and use-after-free.
+.It unix.cstring.BadSizeArg
+Check the size argument passed into C string functions for common
+erroneous patterns.
+.It unix.cstring.NullArg
+Check for null pointers being passed as arguments to C string functions.
+.El
+.\"
+.Sh EXAMPLE
+.Ic scan-build -o /tmp/myhtmldir make -j4
+.Pp
+The above example causes analysis reports to be deposited into
+a subdirectory of
+.Pa /tmp/myhtmldir
+and to run
+.Ic make
+with the
+.Fl j4
+option.
+A different subdirectory is created each time
+.Nm
+analyzes a project.
+The analyzer should support most parallel builds, but not distributed builds.
+.Sh AUTHORS
+.Nm
+was written by
+.An "Ted Kremenek" .
+Documentation contributed by
+.An "James K. Lowden" Aq jklowden@schemamania.org .
diff --git a/linux-x64/clang/share/opt-viewer/opt-diff.py b/linux-x64/clang/share/opt-viewer/opt-diff.py
new file mode 100755
index 0000000..f3bfd18
--- /dev/null
+++ b/linux-x64/clang/share/opt-viewer/opt-diff.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python2.7
+
+from __future__ import print_function
+
+desc = '''Generate the difference of two YAML files into a new YAML file (works on
+pair of directories too). A new attribute 'Added' is set to True or False
+depending whether the entry is added or removed from the first input to the
+next.
+
+The tools requires PyYAML.'''
+
+import yaml
+# Try to use the C parser.
+try:
+ from yaml import CLoader as Loader
+except ImportError:
+ from yaml import Loader
+
+import optrecord
+import argparse
+from collections import defaultdict
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=desc)
+ parser.add_argument(
+ 'yaml_dir_or_file_1',
+ help='An optimization record file or a directory searched for optimization '
+ 'record files that are used as the old version for the comparison')
+ parser.add_argument(
+ 'yaml_dir_or_file_2',
+ help='An optimization record file or a directory searched for optimization '
+ 'record files that are used as the new version for the comparison')
+ parser.add_argument(
+ '--jobs',
+ '-j',
+ default=None,
+ type=int,
+ help='Max job count (defaults to %(default)s, the current CPU count)')
+ parser.add_argument(
+ '--max-size',
+ '-m',
+ default=100000,
+ type=int,
+ help='Maximum number of remarks stored in an output file')
+ parser.add_argument(
+ '--no-progress-indicator',
+ '-n',
+ action='store_true',
+ default=False,
+ help='Do not display any indicator of how many YAML files were read.')
+ parser.add_argument('--output', '-o', default='diff{}.opt.yaml')
+ args = parser.parse_args()
+
+ files1 = optrecord.find_opt_files(args.yaml_dir_or_file_1)
+ files2 = optrecord.find_opt_files(args.yaml_dir_or_file_2)
+
+ print_progress = not args.no_progress_indicator
+ all_remarks1, _, _ = optrecord.gather_results(files1, args.jobs, print_progress)
+ all_remarks2, _, _ = optrecord.gather_results(files2, args.jobs, print_progress)
+
+ added = set(all_remarks2.values()) - set(all_remarks1.values())
+ removed = set(all_remarks1.values()) - set(all_remarks2.values())
+
+ for r in added:
+ r.Added = True
+ for r in removed:
+ r.Added = False
+
+ result = list(added | removed)
+ for r in result:
+ r.recover_yaml_structure()
+
+ for i in range(0, len(result), args.max_size):
+ with open(args.output.format(i / args.max_size), 'w') as stream:
+ yaml.dump_all(result[i:i + args.max_size], stream)
diff --git a/linux-x64/clang/share/opt-viewer/opt-stats.py b/linux-x64/clang/share/opt-viewer/opt-stats.py
new file mode 100755
index 0000000..03de23b
--- /dev/null
+++ b/linux-x64/clang/share/opt-viewer/opt-stats.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python2.7
+
+from __future__ import print_function
+
+desc = '''Generate statistics about optimization records from the YAML files
+generated with -fsave-optimization-record and -fdiagnostics-show-hotness.
+
+The tools requires PyYAML and Pygments Python packages.'''
+
+import optrecord
+import argparse
+import operator
+from collections import defaultdict
+from multiprocessing import cpu_count, Pool
+
+try:
+ from guppy import hpy
+ hp = hpy()
+except ImportError:
+ print("Memory consumption not shown because guppy is not installed")
+ hp = None
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=desc)
+ parser.add_argument(
+ 'yaml_dirs_or_files',
+ nargs='+',
+ help='List of optimization record files or directories searched '
+ 'for optimization record files.')
+ parser.add_argument(
+ '--jobs',
+ '-j',
+ default=None,
+ type=int,
+ help='Max job count (defaults to %(default)s, the current CPU count)')
+ parser.add_argument(
+ '--no-progress-indicator',
+ '-n',
+ action='store_true',
+ default=False,
+ help='Do not display any indicator of how many YAML files were read.')
+ args = parser.parse_args()
+
+ print_progress = not args.no_progress_indicator
+
+ files = optrecord.find_opt_files(*args.yaml_dirs_or_files)
+ if not files:
+ parser.error("No *.opt.yaml files found")
+ sys.exit(1)
+
+ all_remarks, file_remarks, _ = optrecord.gather_results(
+ files, args.jobs, print_progress)
+ if print_progress:
+ print('\n')
+
+ bypass = defaultdict(int)
+ byname = defaultdict(int)
+ for r in optrecord.itervalues(all_remarks):
+ bypass[r.Pass] += 1
+ byname[r.Pass + "/" + r.Name] += 1
+
+ total = len(all_remarks)
+ print("{:24s} {:10d}".format("Total number of remarks", total))
+ if hp:
+ h = hp.heap()
+ print("{:24s} {:10d}".format("Memory per remark",
+ h.size / len(all_remarks)))
+ print('\n')
+
+ print("Top 10 remarks by pass:")
+ for (passname, count) in sorted(bypass.items(), key=operator.itemgetter(1),
+ reverse=True)[:10]:
+ print(" {:30s} {:2.0f}%". format(passname, count * 100. / total))
+
+ print("\nTop 10 remarks:")
+ for (name, count) in sorted(byname.items(), key=operator.itemgetter(1),
+ reverse=True)[:10]:
+ print(" {:30s} {:2.0f}%". format(name, count * 100. / total))
diff --git a/linux-x64/clang/share/opt-viewer/opt-viewer.py b/linux-x64/clang/share/opt-viewer/opt-viewer.py
new file mode 100755
index 0000000..4887043
--- /dev/null
+++ b/linux-x64/clang/share/opt-viewer/opt-viewer.py
@@ -0,0 +1,343 @@
+#!/usr/bin/env python2.7
+
+from __future__ import print_function
+
+import argparse
+import cgi
+import codecs
+import errno
+import functools
+from multiprocessing import cpu_count
+import os.path
+import re
+import shutil
+import sys
+
+from pygments import highlight
+from pygments.lexers.c_cpp import CppLexer
+from pygments.formatters import HtmlFormatter
+
+import optpmap
+import optrecord
+
+
+desc = '''Generate HTML output to visualize optimization records from the YAML files
+generated with -fsave-optimization-record and -fdiagnostics-show-hotness.
+
+The tools requires PyYAML and Pygments Python packages.'''
+
+
+# This allows passing the global context to the child processes.
+class Context:
+ def __init__(self, caller_loc = dict()):
+ # Map function names to their source location for function where inlining happened
+ self.caller_loc = caller_loc
+
+context = Context()
+
+def suppress(remark):
+ if remark.Name == 'sil.Specialized':
+ return remark.getArgDict()['Function'][0].startswith('\"Swift.')
+ elif remark.Name == 'sil.Inlined':
+ return remark.getArgDict()['Callee'][0].startswith(('\"Swift.', '\"specialized Swift.'))
+ return False
+
+class SourceFileRenderer:
+ def __init__(self, source_dir, output_dir, filename, no_highlight):
+ self.filename = filename
+ existing_filename = None
+ if os.path.exists(filename):
+ existing_filename = filename
+ else:
+ fn = os.path.join(source_dir, filename)
+ if os.path.exists(fn):
+ existing_filename = fn
+
+ self.no_highlight = no_highlight
+ self.stream = codecs.open(os.path.join(output_dir, optrecord.html_file_name(filename)), 'w', encoding='utf-8')
+ if existing_filename:
+ self.source_stream = open(existing_filename)
+ else:
+ self.source_stream = None
+ print('''
+<html>
+<h1>Unable to locate file {}</h1>
+</html>
+ '''.format(filename), file=self.stream)
+
+ self.html_formatter = HtmlFormatter(encoding='utf-8')
+ self.cpp_lexer = CppLexer(stripnl=False)
+
+ def render_source_lines(self, stream, line_remarks):
+ file_text = stream.read()
+
+ if self.no_highlight:
+ html_highlighted = file_text.decode('utf-8')
+ else:
+ html_highlighted = highlight(
+ file_text,
+ self.cpp_lexer,
+ self.html_formatter)
+
+ # Note that the API is different between Python 2 and 3. On
+ # Python 3, pygments.highlight() returns a bytes object, so we
+ # have to decode. On Python 2, the output is str but since we
+ # support unicode characters and the output streams is unicode we
+ # decode too.
+ html_highlighted = html_highlighted.decode('utf-8')
+
+ # Take off the header and footer, these must be
+ # reapplied line-wise, within the page structure
+ html_highlighted = html_highlighted.replace('<div class="highlight"><pre>', '')
+ html_highlighted = html_highlighted.replace('</pre></div>', '')
+
+ for (linenum, html_line) in enumerate(html_highlighted.split('\n'), start=1):
+ print(u'''
+<tr>
+<td><a name=\"L{linenum}\">{linenum}</a></td>
+<td></td>
+<td></td>
+<td><div class="highlight"><pre>{html_line}</pre></div></td>
+</tr>'''.format(**locals()), file=self.stream)
+
+ for remark in line_remarks.get(linenum, []):
+ if not suppress(remark):
+ self.render_inline_remarks(remark, html_line)
+
+ def render_inline_remarks(self, r, line):
+ inlining_context = r.DemangledFunctionName
+ dl = context.caller_loc.get(r.Function)
+ if dl:
+ dl_dict = dict(list(dl))
+ link = optrecord.make_link(dl_dict['File'], dl_dict['Line'] - 2)
+ inlining_context = "<a href={link}>{r.DemangledFunctionName}</a>".format(**locals())
+
+ # Column is the number of characters *including* tabs, keep those and
+ # replace everything else with spaces.
+ indent = line[:max(r.Column, 1) - 1]
+ indent = re.sub('\S', ' ', indent)
+
+ print(u'''
+<tr>
+<td></td>
+<td>{r.RelativeHotness}</td>
+<td class=\"column-entry-{r.color}\">{r.PassWithDiffPrefix}</td>
+<td><pre style="display:inline">{indent}</pre><span class=\"column-entry-yellow\"> {r.message} </span></td>
+<td class=\"column-entry-yellow\">{inlining_context}</td>
+</tr>'''.format(**locals()), file=self.stream)
+
+ def render(self, line_remarks):
+ if not self.source_stream:
+ return
+
+ print('''
+<html>
+<title>{}</title>
+<meta charset="utf-8" />
+<head>
+<link rel='stylesheet' type='text/css' href='style.css'>
+</head>
+<body>
+<div class="centered">
+<table class="source">
+<thead>
+<tr>
+<th style="width: 2%">Line</td>
+<th style="width: 3%">Hotness</td>
+<th style="width: 10%">Optimization</td>
+<th style="width: 70%">Source</td>
+<th style="width: 15%">Inline Context</td>
+</tr>
+</thead>
+<tbody>'''.format(os.path.basename(self.filename)), file=self.stream)
+ self.render_source_lines(self.source_stream, line_remarks)
+
+ print('''
+</tbody>
+</table>
+</body>
+</html>''', file=self.stream)
+
+
+class IndexRenderer:
+ def __init__(self, output_dir, should_display_hotness, max_hottest_remarks_on_index):
+ self.stream = codecs.open(os.path.join(output_dir, 'index.html'), 'w', encoding='utf-8')
+ self.should_display_hotness = should_display_hotness
+ self.max_hottest_remarks_on_index = max_hottest_remarks_on_index
+
+ def render_entry(self, r, odd):
+ escaped_name = cgi.escape(r.DemangledFunctionName)
+ print(u'''
+<tr>
+<td class=\"column-entry-{odd}\"><a href={r.Link}>{r.DebugLocString}</a></td>
+<td class=\"column-entry-{odd}\">{r.RelativeHotness}</td>
+<td class=\"column-entry-{odd}\">{escaped_name}</td>
+<td class=\"column-entry-{r.color}\">{r.PassWithDiffPrefix}</td>
+</tr>'''.format(**locals()), file=self.stream)
+
+ def render(self, all_remarks):
+ print('''
+<html>
+<meta charset="utf-8" />
+<head>
+<link rel='stylesheet' type='text/css' href='style.css'>
+</head>
+<body>
+<div class="centered">
+<table>
+<tr>
+<td>Source Location</td>
+<td>Hotness</td>
+<td>Function</td>
+<td>Pass</td>
+</tr>''', file=self.stream)
+
+ max_entries = None
+ if self.should_display_hotness:
+ max_entries = self.max_hottest_remarks_on_index
+
+ for i, remark in enumerate(all_remarks[:max_entries]):
+ if not suppress(remark):
+ self.render_entry(remark, i % 2)
+ print('''
+</table>
+</body>
+</html>''', file=self.stream)
+
+
+def _render_file(source_dir, output_dir, ctx, no_highlight, entry):
+ global context
+ context = ctx
+ filename, remarks = entry
+ SourceFileRenderer(source_dir, output_dir, filename, no_highlight).render(remarks)
+
+
+def map_remarks(all_remarks):
+ # Set up a map between function names and their source location for
+ # function where inlining happened
+ for remark in optrecord.itervalues(all_remarks):
+ if isinstance(remark, optrecord.Passed) and remark.Pass == "inline" and remark.Name == "Inlined":
+ for arg in remark.Args:
+ arg_dict = dict(list(arg))
+ caller = arg_dict.get('Caller')
+ if caller:
+ try:
+ context.caller_loc[caller] = arg_dict['DebugLoc']
+ except KeyError:
+ pass
+
+
+def generate_report(all_remarks,
+ file_remarks,
+ source_dir,
+ output_dir,
+ no_highlight,
+ should_display_hotness,
+ max_hottest_remarks_on_index,
+ num_jobs,
+ should_print_progress):
+ try:
+ os.makedirs(output_dir)
+ except OSError as e:
+ if e.errno == errno.EEXIST and os.path.isdir(output_dir):
+ pass
+ else:
+ raise
+
+ if should_print_progress:
+ print('Rendering index page...')
+ if should_display_hotness:
+ sorted_remarks = sorted(optrecord.itervalues(all_remarks), key=lambda r: (r.Hotness, r.File, r.Line, r.Column, r.PassWithDiffPrefix, r.yaml_tag, r.Function), reverse=True)
+ else:
+ sorted_remarks = sorted(optrecord.itervalues(all_remarks), key=lambda r: (r.File, r.Line, r.Column, r.PassWithDiffPrefix, r.yaml_tag, r.Function))
+ IndexRenderer(output_dir, should_display_hotness, max_hottest_remarks_on_index).render(sorted_remarks)
+
+ shutil.copy(os.path.join(os.path.dirname(os.path.realpath(__file__)),
+ "style.css"), output_dir)
+
+ _render_file_bound = functools.partial(_render_file, source_dir, output_dir, context, no_highlight)
+ if should_print_progress:
+ print('Rendering HTML files...')
+ optpmap.pmap(_render_file_bound,
+ file_remarks.items(),
+ num_jobs,
+ should_print_progress)
+
+
+def main():
+ parser = argparse.ArgumentParser(description=desc)
+ parser.add_argument(
+ 'yaml_dirs_or_files',
+ nargs='+',
+ help='List of optimization record files or directories searched '
+ 'for optimization record files.')
+ parser.add_argument(
+ '--output-dir',
+ '-o',
+ default='html',
+ help='Path to a directory where generated HTML files will be output. '
+ 'If the directory does not already exist, it will be created. '
+ '"%(default)s" by default.')
+ parser.add_argument(
+ '--jobs',
+ '-j',
+ default=None,
+ type=int,
+ help='Max job count (defaults to %(default)s, the current CPU count)')
+ parser.add_argument(
+ '--source-dir',
+ '-s',
+ default='',
+ help='set source directory')
+ parser.add_argument(
+ '--no-progress-indicator',
+ '-n',
+ action='store_true',
+ default=False,
+ help='Do not display any indicator of how many YAML files were read '
+ 'or rendered into HTML.')
+ parser.add_argument(
+ '--max-hottest-remarks-on-index',
+ default=1000,
+ type=int,
+ help='Maximum number of the hottest remarks to appear on the index page')
+ parser.add_argument(
+ '--no-highlight',
+ action='store_true',
+ default=False,
+ help='Do not use a syntax highlighter when rendering the source code')
+ parser.add_argument(
+ '--demangler',
+ help='Set the demangler to be used (defaults to %s)' % optrecord.Remark.default_demangler)
+
+ # Do not make this a global variable. Values needed to be propagated through
+ # to individual classes and functions to be portable with multiprocessing across
+ # Windows and non-Windows.
+ args = parser.parse_args()
+
+ print_progress = not args.no_progress_indicator
+ if args.demangler:
+ optrecord.Remark.set_demangler(args.demangler)
+
+ files = optrecord.find_opt_files(*args.yaml_dirs_or_files)
+ if not files:
+ parser.error("No *.opt.yaml files found")
+ sys.exit(1)
+
+ all_remarks, file_remarks, should_display_hotness = \
+ optrecord.gather_results(files, args.jobs, print_progress)
+
+ map_remarks(all_remarks)
+
+ generate_report(all_remarks,
+ file_remarks,
+ args.source_dir,
+ args.output_dir,
+ args.no_highlight,
+ should_display_hotness,
+ args.max_hottest_remarks_on_index,
+ args.jobs,
+ print_progress)
+
+if __name__ == '__main__':
+ main()
diff --git a/linux-x64/clang/share/opt-viewer/optpmap.py b/linux-x64/clang/share/opt-viewer/optpmap.py
new file mode 100755
index 0000000..db6b079
--- /dev/null
+++ b/linux-x64/clang/share/opt-viewer/optpmap.py
@@ -0,0 +1,56 @@
+import sys
+import multiprocessing
+
+
+_current = None
+_total = None
+
+
+def _init(current, total):
+ global _current
+ global _total
+ _current = current
+ _total = total
+
+
+def _wrapped_func(func_and_args):
+ func, argument, should_print_progress = func_and_args
+
+ if should_print_progress:
+ with _current.get_lock():
+ _current.value += 1
+ sys.stdout.write('\r\t{} of {}'.format(_current.value, _total.value))
+ sys.stdout.flush()
+
+ return func(argument)
+
+
+def pmap(func, iterable, processes, should_print_progress, *args, **kwargs):
+ """
+ A parallel map function that reports on its progress.
+
+ Applies `func` to every item of `iterable` and return a list of the
+ results. If `processes` is greater than one, a process pool is used to run
+ the functions in parallel. `should_print_progress` is a boolean value that
+ indicates whether a string 'N of M' should be printed to indicate how many
+ of the functions have finished being run.
+ """
+ global _current
+ global _total
+ _current = multiprocessing.Value('i', 0)
+ _total = multiprocessing.Value('i', len(iterable))
+
+ func_and_args = [(func, arg, should_print_progress,) for arg in iterable]
+ if processes == 1:
+ result = map(_wrapped_func, func_and_args, *args, **kwargs)
+ else:
+ pool = multiprocessing.Pool(initializer=_init,
+ initargs=(_current, _total,),
+ processes=processes)
+ result = pool.map(_wrapped_func, func_and_args, *args, **kwargs)
+ pool.close()
+ pool.join()
+
+ if should_print_progress:
+ sys.stdout.write('\r')
+ return result
diff --git a/linux-x64/clang/share/opt-viewer/optrecord.py b/linux-x64/clang/share/opt-viewer/optrecord.py
new file mode 100755
index 0000000..8cf22ee
--- /dev/null
+++ b/linux-x64/clang/share/opt-viewer/optrecord.py
@@ -0,0 +1,333 @@
+#!/usr/bin/env python2.7
+
+from __future__ import print_function
+
+import yaml
+# Try to use the C parser.
+try:
+ from yaml import CLoader as Loader
+except ImportError:
+ print("For faster parsing, you may want to install libYAML for PyYAML")
+ from yaml import Loader
+
+import cgi
+from collections import defaultdict
+import fnmatch
+import functools
+from multiprocessing import Lock
+import os, os.path
+import subprocess
+try:
+ # The previously builtin function `intern()` was moved
+ # to the `sys` module in Python 3.
+ from sys import intern
+except:
+ pass
+
+import optpmap
+
+try:
+ dict.iteritems
+except AttributeError:
+ # Python 3
+ def itervalues(d):
+ return iter(d.values())
+ def iteritems(d):
+ return iter(d.items())
+else:
+ # Python 2
+ def itervalues(d):
+ return d.itervalues()
+ def iteritems(d):
+ return d.iteritems()
+
+
+def html_file_name(filename):
+ return filename.replace('/', '_').replace('#', '_') + ".html"
+
+
+def make_link(File, Line):
+ return "\"{}#L{}\"".format(html_file_name(File), Line)
+
+
+class Remark(yaml.YAMLObject):
+ # Work-around for http://pyyaml.org/ticket/154.
+ yaml_loader = Loader
+
+ default_demangler = 'c++filt -n'
+ demangler_proc = None
+
+ @classmethod
+ def set_demangler(cls, demangler):
+ cls.demangler_proc = subprocess.Popen(demangler.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ cls.demangler_lock = Lock()
+
+ @classmethod
+ def demangle(cls, name):
+ with cls.demangler_lock:
+ cls.demangler_proc.stdin.write((name + '\n').encode('utf-8'))
+ cls.demangler_proc.stdin.flush()
+ return cls.demangler_proc.stdout.readline().rstrip().decode('utf-8')
+
+ # Intern all strings since we have lot of duplication across filenames,
+ # remark text.
+ #
+ # Change Args from a list of dicts to a tuple of tuples. This saves
+ # memory in two ways. One, a small tuple is significantly smaller than a
+ # small dict. Two, using tuple instead of list allows Args to be directly
+ # used as part of the key (in Python only immutable types are hashable).
+ def _reduce_memory(self):
+ self.Pass = intern(self.Pass)
+ self.Name = intern(self.Name)
+ try:
+ # Can't intern unicode strings.
+ self.Function = intern(self.Function)
+ except:
+ pass
+
+ def _reduce_memory_dict(old_dict):
+ new_dict = dict()
+ for (k, v) in iteritems(old_dict):
+ if type(k) is str:
+ k = intern(k)
+
+ if type(v) is str:
+ v = intern(v)
+ elif type(v) is dict:
+ # This handles [{'Caller': ..., 'DebugLoc': { 'File': ... }}]
+ v = _reduce_memory_dict(v)
+ new_dict[k] = v
+ return tuple(new_dict.items())
+
+ self.Args = tuple([_reduce_memory_dict(arg_dict) for arg_dict in self.Args])
+
+ # The inverse operation of the dictonary-related memory optimization in
+ # _reduce_memory_dict. E.g.
+ # (('DebugLoc', (('File', ...) ... ))) -> [{'DebugLoc': {'File': ...} ....}]
+ def recover_yaml_structure(self):
+ def tuple_to_dict(t):
+ d = dict()
+ for (k, v) in t:
+ if type(v) is tuple:
+ v = tuple_to_dict(v)
+ d[k] = v
+ return d
+
+ self.Args = [tuple_to_dict(arg_tuple) for arg_tuple in self.Args]
+
+ def canonicalize(self):
+ if not hasattr(self, 'Hotness'):
+ self.Hotness = 0
+ if not hasattr(self, 'Args'):
+ self.Args = []
+ self._reduce_memory()
+
+ @property
+ def File(self):
+ return self.DebugLoc['File']
+
+ @property
+ def Line(self):
+ return int(self.DebugLoc['Line'])
+
+ @property
+ def Column(self):
+ return self.DebugLoc['Column']
+
+ @property
+ def DebugLocString(self):
+ return "{}:{}:{}".format(self.File, self.Line, self.Column)
+
+ @property
+ def DemangledFunctionName(self):
+ return self.demangle(self.Function)
+
+ @property
+ def Link(self):
+ return make_link(self.File, self.Line)
+
+ def getArgString(self, mapping):
+ mapping = dict(list(mapping))
+ dl = mapping.get('DebugLoc')
+ if dl:
+ del mapping['DebugLoc']
+
+ assert(len(mapping) == 1)
+ (key, value) = list(mapping.items())[0]
+
+ if key == 'Caller' or key == 'Callee' or key == 'DirectCallee':
+ value = cgi.escape(self.demangle(value))
+
+ if dl and key != 'Caller':
+ dl_dict = dict(list(dl))
+ return u"<a href={}>{}</a>".format(
+ make_link(dl_dict['File'], dl_dict['Line']), value)
+ else:
+ return value
+
+ # Return a cached dictionary for the arguments. The key for each entry is
+ # the argument key (e.g. 'Callee' for inlining remarks. The value is a
+ # list containing the value (e.g. for 'Callee' the function) and
+ # optionally a DebugLoc.
+ def getArgDict(self):
+ if hasattr(self, 'ArgDict'):
+ return self.ArgDict
+ self.ArgDict = {}
+ for arg in self.Args:
+ if len(arg) == 2:
+ if arg[0][0] == 'DebugLoc':
+ dbgidx = 0
+ else:
+ assert(arg[1][0] == 'DebugLoc')
+ dbgidx = 1
+
+ key = arg[1 - dbgidx][0]
+ entry = (arg[1 - dbgidx][1], arg[dbgidx][1])
+ else:
+ arg = arg[0]
+ key = arg[0]
+ entry = (arg[1], )
+
+ self.ArgDict[key] = entry
+ return self.ArgDict
+
+ def getDiffPrefix(self):
+ if hasattr(self, 'Added'):
+ if self.Added:
+ return '+'
+ else:
+ return '-'
+ return ''
+
+ @property
+ def PassWithDiffPrefix(self):
+ return self.getDiffPrefix() + self.Pass
+
+ @property
+ def message(self):
+ # Args is a list of mappings (dictionaries)
+ values = [self.getArgString(mapping) for mapping in self.Args]
+ return "".join(values)
+
+ @property
+ def RelativeHotness(self):
+ if self.max_hotness:
+ return "{0:.2f}%".format(self.Hotness * 100. / self.max_hotness)
+ else:
+ return ''
+
+ @property
+ def key(self):
+ return (self.__class__, self.PassWithDiffPrefix, self.Name, self.File,
+ self.Line, self.Column, self.Function, self.Args)
+
+ def __hash__(self):
+ return hash(self.key)
+
+ def __eq__(self, other):
+ return self.key == other.key
+
+ def __repr__(self):
+ return str(self.key)
+
+
+class Analysis(Remark):
+ yaml_tag = '!Analysis'
+
+ @property
+ def color(self):
+ return "white"
+
+
+class AnalysisFPCommute(Analysis):
+ yaml_tag = '!AnalysisFPCommute'
+
+
+class AnalysisAliasing(Analysis):
+ yaml_tag = '!AnalysisAliasing'
+
+
+class Passed(Remark):
+ yaml_tag = '!Passed'
+
+ @property
+ def color(self):
+ return "green"
+
+
+class Missed(Remark):
+ yaml_tag = '!Missed'
+
+ @property
+ def color(self):
+ return "red"
+
+
+def get_remarks(input_file):
+ max_hotness = 0
+ all_remarks = dict()
+ file_remarks = defaultdict(functools.partial(defaultdict, list))
+
+ with open(input_file) as f:
+ docs = yaml.load_all(f, Loader=Loader)
+ for remark in docs:
+ remark.canonicalize()
+ # Avoid remarks withoug debug location or if they are duplicated
+ if not hasattr(remark, 'DebugLoc') or remark.key in all_remarks:
+ continue
+ all_remarks[remark.key] = remark
+
+ file_remarks[remark.File][remark.Line].append(remark)
+
+ # If we're reading a back a diff yaml file, max_hotness is already
+ # captured which may actually be less than the max hotness found
+ # in the file.
+ if hasattr(remark, 'max_hotness'):
+ max_hotness = remark.max_hotness
+ max_hotness = max(max_hotness, remark.Hotness)
+
+ return max_hotness, all_remarks, file_remarks
+
+
+def gather_results(filenames, num_jobs, should_print_progress):
+ if should_print_progress:
+ print('Reading YAML files...')
+ if not Remark.demangler_proc:
+ Remark.set_demangler(Remark.default_demangler)
+ remarks = optpmap.pmap(
+ get_remarks, filenames, num_jobs, should_print_progress)
+ max_hotness = max(entry[0] for entry in remarks)
+
+ def merge_file_remarks(file_remarks_job, all_remarks, merged):
+ for filename, d in iteritems(file_remarks_job):
+ for line, remarks in iteritems(d):
+ for remark in remarks:
+ # Bring max_hotness into the remarks so that
+ # RelativeHotness does not depend on an external global.
+ remark.max_hotness = max_hotness
+ if remark.key not in all_remarks:
+ merged[filename][line].append(remark)
+
+ all_remarks = dict()
+ file_remarks = defaultdict(functools.partial(defaultdict, list))
+ for _, all_remarks_job, file_remarks_job in remarks:
+ merge_file_remarks(file_remarks_job, all_remarks, file_remarks)
+ all_remarks.update(all_remarks_job)
+
+ return all_remarks, file_remarks, max_hotness != 0
+
+
+def find_opt_files(*dirs_or_files):
+ all = []
+ for dir_or_file in dirs_or_files:
+ if os.path.isfile(dir_or_file):
+ all.append(dir_or_file)
+ else:
+ for dir, subdirs, files in os.walk(dir_or_file):
+ # Exclude mounted directories and symlinks (os.walk default).
+ subdirs[:] = [d for d in subdirs
+ if not os.path.ismount(os.path.join(dir, d))]
+ for file in files:
+ if fnmatch.fnmatch(file, "*.opt.yaml*"):
+ all.append(os.path.join(dir, file))
+ return all
diff --git a/linux-x64/clang/share/opt-viewer/style.css b/linux-x64/clang/share/opt-viewer/style.css
new file mode 100755
index 0000000..0d3347c
--- /dev/null
+++ b/linux-x64/clang/share/opt-viewer/style.css
@@ -0,0 +1,208 @@
+.source {
+ table-layout: fixed;
+ width: 100%;
+ white-space: nowrap;
+}
+.source td {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.red {
+ background-color: #ffd0d0;
+}
+.cyan {
+ background-color: cyan;
+}
+body {
+ font-family: -apple-system, sans-serif;
+}
+pre {
+ margin-top: 0px !important;
+ margin-bottom: 0px !important;
+}
+.source-name-title {
+ padding: 5px 10px;
+ border-bottom: 1px solid #dbdbdb;
+ background-color: #eee;
+ line-height: 35px;
+}
+.centered {
+ display: table;
+ margin-left: left;
+ margin-right: auto;
+ border: 1px solid #dbdbdb;
+ border-radius: 3px;
+}
+.expansion-view {
+ background-color: rgba(0, 0, 0, 0);
+ margin-left: 0px;
+ margin-top: 5px;
+ margin-right: 5px;
+ margin-bottom: 5px;
+ border: 1px solid #dbdbdb;
+ border-radius: 3px;
+}
+table {
+ border-collapse: collapse;
+}
+.light-row {
+ background: #ffffff;
+ border: 1px solid #dbdbdb;
+}
+.column-entry {
+ text-align: right;
+}
+.column-entry-left {
+ text-align: left;
+}
+.column-entry-white {
+ text-align: right;
+ background-color: #ffffff;
+}
+.column-entry-red {
+ text-align: right;
+ background-color: #ffd0d0;
+}
+.column-entry-green {
+ text-align: right;
+ background-color: #d0ffd0;
+}
+.column-entry-yellow {
+ text-align: left;
+ background-color: #ffe1a6;
+}
+.column-entry-0 {
+ background-color: #ffffff;
+}
+.column-entry-1 {
+ background-color: #eeeeee;
+}
+.line-number {
+ text-align: right;
+ color: #aaa;
+}
+.covered-line {
+ text-align: right;
+ color: #0080ff;
+}
+.uncovered-line {
+ text-align: right;
+ color: #ff3300;
+}
+.tooltip {
+ position: relative;
+ display: inline;
+ background-color: #b3e6ff;
+ text-decoration: none;
+}
+.tooltip span.tooltip-content {
+ position: absolute;
+ width: 100px;
+ margin-left: -50px;
+ color: #FFFFFF;
+ background: #000000;
+ height: 30px;
+ line-height: 30px;
+ text-align: center;
+ visibility: hidden;
+ border-radius: 6px;
+}
+.tooltip span.tooltip-content:after {
+ content: '';
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ margin-left: -8px;
+ width: 0; height: 0;
+ border-top: 8px solid #000000;
+ border-right: 8px solid transparent;
+ border-left: 8px solid transparent;
+}
+:hover.tooltip span.tooltip-content {
+ visibility: visible;
+ opacity: 0.8;
+ bottom: 30px;
+ left: 50%;
+ z-index: 999;
+}
+th, td {
+ vertical-align: top;
+ padding: 2px 5px;
+ border-collapse: collapse;
+ border-right: solid 1px #eee;
+ border-left: solid 1px #eee;
+}
+td:first-child {
+ border-left: none;
+}
+td:last-child {
+ border-right: none;
+}
+
+/* Generated with pygmentize -S colorful -f html >> style.css */
+
+.hll { background-color: #ffffcc }
+.c { color: #888888 } /* Comment */
+.err { color: #FF0000; background-color: #FFAAAA } /* Error */
+.k { color: #008800; font-weight: bold } /* Keyword */
+.o { color: #333333 } /* Operator */
+.ch { color: #888888 } /* Comment.Hashbang */
+.cm { color: #888888 } /* Comment.Multiline */
+.cp { color: #557799 } /* Comment.Preproc */
+.cpf { color: #888888 } /* Comment.PreprocFile */
+.c1 { color: #888888 } /* Comment.Single */
+.cs { color: #cc0000; font-weight: bold } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0044DD } /* Generic.Traceback */
+.kc { color: #008800; font-weight: bold } /* Keyword.Constant */
+.kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #003388; font-weight: bold } /* Keyword.Pseudo */
+.kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #333399; font-weight: bold } /* Keyword.Type */
+.m { color: #6600EE; font-weight: bold } /* Literal.Number */
+.s { background-color: #fff0f0 } /* Literal.String */
+.na { color: #0000CC } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #BB0066; font-weight: bold } /* Name.Class */
+.no { color: #003366; font-weight: bold } /* Name.Constant */
+.nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.ni { color: #880000; font-weight: bold } /* Name.Entity */
+.ne { color: #FF0000; font-weight: bold } /* Name.Exception */
+.nf { color: #0066BB; font-weight: bold } /* Name.Function */
+.nl { color: #997700; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #007700 } /* Name.Tag */
+.nv { color: #996633 } /* Name.Variable */
+.ow { color: #000000; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mb { color: #6600EE; font-weight: bold } /* Literal.Number.Bin */
+.mf { color: #6600EE; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #005588; font-weight: bold } /* Literal.Number.Hex */
+.mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
+.mo { color: #4400EE; font-weight: bold } /* Literal.Number.Oct */
+.sb { background-color: #fff0f0 } /* Literal.String.Backtick */
+.sc { color: #0044DD } /* Literal.String.Char */
+.sd { color: #DD4422 } /* Literal.String.Doc */
+.s2 { background-color: #fff0f0 } /* Literal.String.Double */
+.se { color: #666666; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
+.sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
+.si { background-color: #eeeeee } /* Literal.String.Interpol */
+.sx { color: #DD2200; background-color: #fff0f0 } /* Literal.String.Other */
+.sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
+.s1 { background-color: #fff0f0 } /* Literal.String.Single */
+.ss { color: #AA6600 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #336699 } /* Name.Variable.Class */
+.vg { color: #dd7700; font-weight: bold } /* Name.Variable.Global */
+.vi { color: #3333BB } /* Name.Variable.Instance */
+.il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
diff --git a/linux-x64/clang/share/scan-build/scanview.css b/linux-x64/clang/share/scan-build/scanview.css
new file mode 100644
index 0000000..cf8a5a6
--- /dev/null
+++ b/linux-x64/clang/share/scan-build/scanview.css
@@ -0,0 +1,62 @@
+body { color:#000000; background-color:#ffffff }
+body { font-family: Helvetica, sans-serif; font-size:9pt }
+h1 { font-size: 14pt; }
+h2 { font-size: 12pt; }
+table { font-size:9pt }
+table { border-spacing: 0px; border: 1px solid black }
+th, table thead {
+ background-color:#eee; color:#666666;
+ font-weight: bold; cursor: default;
+ text-align:center;
+ font-weight: bold; font-family: Verdana;
+ white-space:nowrap;
+}
+.W { font-size:0px }
+th, td { padding:5px; padding-left:8px; text-align:left }
+td.SUMM_DESC { padding-left:12px }
+td.DESC { white-space:pre }
+td.Q { text-align:right }
+td { text-align:left }
+tbody.scrollContent { overflow:auto }
+
+table.form_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+table.form_inner_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 0px;
+}
+
+table.form {
+ background-color: #999;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+td.form_label {
+ text-align: right;
+ vertical-align: top;
+}
+/* For one line entires */
+td.form_clabel {
+ text-align: right;
+ vertical-align: center;
+}
+td.form_value {
+ text-align: left;
+ vertical-align: top;
+}
+td.form_submit {
+ text-align: right;
+ vertical-align: top;
+}
+
+h1.SubmitFail {
+ color: #f00;
+}
+h1.SubmitOk {
+}
diff --git a/linux-x64/clang/share/scan-build/sorttable.js b/linux-x64/clang/share/scan-build/sorttable.js
new file mode 100644
index 0000000..32faa07
--- /dev/null
+++ b/linux-x64/clang/share/scan-build/sorttable.js
@@ -0,0 +1,492 @@
+/*
+ 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 ? ' <font face="webdings">5</font>' : ' ▴';
+ 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 ? ' <font face="webdings">6</font>' : ' ▾';
+ 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 ? ' <font face="webdings">6</font>' : ' ▾';
+ 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);
+ }
+};
diff --git a/linux-x64/clang/share/scan-view/FileRadar.scpt b/linux-x64/clang/share/scan-view/FileRadar.scpt
new file mode 100644
index 0000000..1c74552
--- /dev/null
+++ b/linux-x64/clang/share/scan-view/FileRadar.scpt
Binary files differ
diff --git a/linux-x64/clang/share/scan-view/GetRadarVersion.scpt b/linux-x64/clang/share/scan-view/GetRadarVersion.scpt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/linux-x64/clang/share/scan-view/GetRadarVersion.scpt
diff --git a/linux-x64/clang/share/scan-view/Reporter.py b/linux-x64/clang/share/scan-view/Reporter.py
new file mode 100644
index 0000000..800af03
--- /dev/null
+++ b/linux-x64/clang/share/scan-view/Reporter.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""Methods for reporting bugs."""
+
+import subprocess, sys, os
+
+__all__ = ['ReportFailure', 'BugReport', 'getReporters']
+
+#
+
+class ReportFailure(Exception):
+ """Generic exception for failures in bug reporting."""
+ def __init__(self, value):
+ self.value = value
+
+# Collect information about a bug.
+
+class BugReport:
+ def __init__(self, title, description, files):
+ self.title = title
+ self.description = description
+ self.files = files
+
+# Reporter interfaces.
+
+import os
+
+import email, mimetypes, smtplib
+from email import encoders
+from email.message import Message
+from email.mime.base import MIMEBase
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+
+#===------------------------------------------------------------------------===#
+# ReporterParameter
+#===------------------------------------------------------------------------===#
+
+class ReporterParameter:
+ def __init__(self, n):
+ self.name = n
+ def getName(self):
+ return self.name
+ def getValue(self,r,bugtype,getConfigOption):
+ return getConfigOption(r.getName(),self.getName())
+ def saveConfigValue(self):
+ return True
+
+class TextParameter (ReporterParameter):
+ def getHTML(self,r,bugtype,getConfigOption):
+ return """\
+<tr>
+<td class="form_clabel">%s:</td>
+<td class="form_value"><input type="text" name="%s_%s" value="%s"></td>
+</tr>"""%(self.getName(),r.getName(),self.getName(),self.getValue(r,bugtype,getConfigOption))
+
+class SelectionParameter (ReporterParameter):
+ def __init__(self, n, values):
+ ReporterParameter.__init__(self,n)
+ self.values = values
+
+ def getHTML(self,r,bugtype,getConfigOption):
+ default = self.getValue(r,bugtype,getConfigOption)
+ return """\
+<tr>
+<td class="form_clabel">%s:</td><td class="form_value"><select name="%s_%s">
+%s
+</select></td>"""%(self.getName(),r.getName(),self.getName(),'\n'.join(["""\
+<option value="%s"%s>%s</option>"""%(o[0],
+ o[0] == default and ' selected="selected"' or '',
+ o[1]) for o in self.values]))
+
+#===------------------------------------------------------------------------===#
+# Reporters
+#===------------------------------------------------------------------------===#
+
+class EmailReporter:
+ def getName(self):
+ return 'Email'
+
+ def getParameters(self):
+ return map(lambda x:TextParameter(x),['To', 'From', 'SMTP Server', 'SMTP Port'])
+
+ # Lifted from python email module examples.
+ def attachFile(self, outer, path):
+ # Guess the content type based on the file's extension. Encoding
+ # will be ignored, although we should check for simple things like
+ # gzip'd or compressed files.
+ ctype, encoding = mimetypes.guess_type(path)
+ if ctype is None or encoding is not None:
+ # No guess could be made, or the file is encoded (compressed), so
+ # use a generic bag-of-bits type.
+ ctype = 'application/octet-stream'
+ maintype, subtype = ctype.split('/', 1)
+ if maintype == 'text':
+ fp = open(path)
+ # Note: we should handle calculating the charset
+ msg = MIMEText(fp.read(), _subtype=subtype)
+ fp.close()
+ else:
+ fp = open(path, 'rb')
+ msg = MIMEBase(maintype, subtype)
+ msg.set_payload(fp.read())
+ fp.close()
+ # Encode the payload using Base64
+ encoders.encode_base64(msg)
+ # Set the filename parameter
+ msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(path))
+ outer.attach(msg)
+
+ def fileReport(self, report, parameters):
+ mainMsg = """\
+BUG REPORT
+---
+Title: %s
+Description: %s
+"""%(report.title, report.description)
+
+ if not parameters.get('To'):
+ raise ReportFailure('No "To" address specified.')
+ if not parameters.get('From'):
+ raise ReportFailure('No "From" address specified.')
+
+ msg = MIMEMultipart()
+ msg['Subject'] = 'BUG REPORT: %s'%(report.title)
+ # FIXME: Get config parameters
+ msg['To'] = parameters.get('To')
+ msg['From'] = parameters.get('From')
+ msg.preamble = mainMsg
+
+ msg.attach(MIMEText(mainMsg, _subtype='text/plain'))
+ for file in report.files:
+ self.attachFile(msg, file)
+
+ try:
+ s = smtplib.SMTP(host=parameters.get('SMTP Server'),
+ port=parameters.get('SMTP Port'))
+ s.sendmail(msg['From'], msg['To'], msg.as_string())
+ s.close()
+ except:
+ raise ReportFailure('Unable to send message via SMTP.')
+
+ return "Message sent!"
+
+class BugzillaReporter:
+ def getName(self):
+ return 'Bugzilla'
+
+ def getParameters(self):
+ return map(lambda x:TextParameter(x),['URL','Product'])
+
+ def fileReport(self, report, parameters):
+ raise NotImplementedError
+
+
+class RadarClassificationParameter(SelectionParameter):
+ def __init__(self):
+ SelectionParameter.__init__(self,"Classification",
+ [['1', 'Security'], ['2', 'Crash/Hang/Data Loss'],
+ ['3', 'Performance'], ['4', 'UI/Usability'],
+ ['6', 'Serious Bug'], ['7', 'Other']])
+
+ def saveConfigValue(self):
+ return False
+
+ def getValue(self,r,bugtype,getConfigOption):
+ if bugtype.find("leak") != -1:
+ return '3'
+ elif bugtype.find("dereference") != -1:
+ return '2'
+ elif bugtype.find("missing ivar release") != -1:
+ return '3'
+ else:
+ return '7'
+
+class RadarReporter:
+ @staticmethod
+ def isAvailable():
+ # FIXME: Find this .scpt better
+ path = os.path.join(os.path.dirname(__file__),'../share/scan-view/GetRadarVersion.scpt')
+ try:
+ p = subprocess.Popen(['osascript',path],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ except:
+ return False
+ data,err = p.communicate()
+ res = p.wait()
+ # FIXME: Check version? Check for no errors?
+ return res == 0
+
+ def getName(self):
+ return 'Radar'
+
+ def getParameters(self):
+ return [ TextParameter('Component'), TextParameter('Component Version'),
+ RadarClassificationParameter() ]
+
+ def fileReport(self, report, parameters):
+ component = parameters.get('Component', '')
+ componentVersion = parameters.get('Component Version', '')
+ classification = parameters.get('Classification', '')
+ personID = ""
+ diagnosis = ""
+ config = ""
+
+ if not component.strip():
+ component = 'Bugs found by clang Analyzer'
+ if not componentVersion.strip():
+ componentVersion = 'X'
+
+ script = os.path.join(os.path.dirname(__file__),'../share/scan-view/FileRadar.scpt')
+ args = ['osascript', script, component, componentVersion, classification, personID, report.title,
+ report.description, diagnosis, config] + map(os.path.abspath, report.files)
+# print >>sys.stderr, args
+ try:
+ p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ except:
+ raise ReportFailure("Unable to file radar (AppleScript failure).")
+ data, err = p.communicate()
+ res = p.wait()
+
+ if res:
+ raise ReportFailure("Unable to file radar (AppleScript failure).")
+
+ try:
+ values = eval(data)
+ except:
+ raise ReportFailure("Unable to process radar results.")
+
+ # We expect (int: bugID, str: message)
+ if len(values) != 2 or not isinstance(values[0], int):
+ raise ReportFailure("Unable to process radar results.")
+
+ bugID,message = values
+ bugID = int(bugID)
+
+ if not bugID:
+ raise ReportFailure(message)
+
+ return "Filed: <a href=\"rdar://%d/\">%d</a>"%(bugID,bugID)
+
+###
+
+def getReporters():
+ reporters = []
+ if RadarReporter.isAvailable():
+ reporters.append(RadarReporter())
+ reporters.append(EmailReporter())
+ return reporters
+
diff --git a/linux-x64/clang/share/scan-view/ScanView.py b/linux-x64/clang/share/scan-view/ScanView.py
new file mode 100644
index 0000000..7dc0351
--- /dev/null
+++ b/linux-x64/clang/share/scan-view/ScanView.py
@@ -0,0 +1,767 @@
+import BaseHTTPServer
+import SimpleHTTPServer
+import os
+import sys
+import urllib, urlparse
+import posixpath
+import StringIO
+import re
+import shutil
+import threading
+import time
+import socket
+import itertools
+
+import Reporter
+import ConfigParser
+
+###
+# Various patterns matched or replaced by server.
+
+kReportFileRE = re.compile('(.*/)?report-(.*)\\.html')
+
+kBugKeyValueRE = re.compile('<!-- BUG([^ ]*) (.*) -->')
+
+# <!-- REPORTPROBLEM file="crashes/clang_crash_ndSGF9.mi" stderr="crashes/clang_crash_ndSGF9.mi.stderr.txt" info="crashes/clang_crash_ndSGF9.mi.info" -->
+
+kReportCrashEntryRE = re.compile('<!-- REPORTPROBLEM (.*?)-->')
+kReportCrashEntryKeyValueRE = re.compile(' ?([^=]+)="(.*?)"')
+
+kReportReplacements = []
+
+# Add custom javascript.
+kReportReplacements.append((re.compile('<!-- SUMMARYENDHEAD -->'), """\
+<script language="javascript" type="text/javascript">
+function load(url) {
+ if (window.XMLHttpRequest) {
+ req = new XMLHttpRequest();
+ } else if (window.ActiveXObject) {
+ req = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ if (req != undefined) {
+ req.open("GET", url, true);
+ req.send("");
+ }
+}
+</script>"""))
+
+# Insert additional columns.
+kReportReplacements.append((re.compile('<!-- REPORTBUGCOL -->'),
+ '<td></td><td></td>'))
+
+# Insert report bug and open file links.
+kReportReplacements.append((re.compile('<!-- REPORTBUG id="report-(.*)\\.html" -->'),
+ ('<td class="Button"><a href="report/\\1">Report Bug</a></td>' +
+ '<td class="Button"><a href="javascript:load(\'open/\\1\')">Open File</a></td>')))
+
+kReportReplacements.append((re.compile('<!-- REPORTHEADER -->'),
+ '<h3><a href="/">Summary</a> > Report %(report)s</h3>'))
+
+kReportReplacements.append((re.compile('<!-- REPORTSUMMARYEXTRA -->'),
+ '<td class="Button"><a href="report/%(report)s">Report Bug</a></td>'))
+
+# Insert report crashes link.
+
+# Disabled for the time being until we decide exactly when this should
+# be enabled. Also the radar reporter needs to be fixed to report
+# multiple files.
+
+#kReportReplacements.append((re.compile('<!-- REPORTCRASHES -->'),
+# '<br>These files will automatically be attached to ' +
+# 'reports filed here: <a href="report_crashes">Report Crashes</a>.'))
+
+###
+# Other simple parameters
+
+kShare = posixpath.join(posixpath.dirname(__file__), '../share/scan-view')
+kConfigPath = os.path.expanduser('~/.scanview.cfg')
+
+###
+
+__version__ = "0.1"
+
+__all__ = ["create_server"]
+
+class ReporterThread(threading.Thread):
+ def __init__(self, report, reporter, parameters, server):
+ threading.Thread.__init__(self)
+ self.report = report
+ self.server = server
+ self.reporter = reporter
+ self.parameters = parameters
+ self.success = False
+ self.status = None
+
+ def run(self):
+ result = None
+ try:
+ if self.server.options.debug:
+ print >>sys.stderr, "%s: SERVER: submitting bug."%(sys.argv[0],)
+ self.status = self.reporter.fileReport(self.report, self.parameters)
+ self.success = True
+ time.sleep(3)
+ if self.server.options.debug:
+ print >>sys.stderr, "%s: SERVER: submission complete."%(sys.argv[0],)
+ except Reporter.ReportFailure,e:
+ self.status = e.value
+ except Exception,e:
+ s = StringIO.StringIO()
+ import traceback
+ print >>s,'<b>Unhandled Exception</b><br><pre>'
+ traceback.print_exc(e,file=s)
+ print >>s,'</pre>'
+ self.status = s.getvalue()
+
+class ScanViewServer(BaseHTTPServer.HTTPServer):
+ def __init__(self, address, handler, root, reporters, options):
+ BaseHTTPServer.HTTPServer.__init__(self, address, handler)
+ self.root = root
+ self.reporters = reporters
+ self.options = options
+ self.halted = False
+ self.config = None
+ self.load_config()
+
+ def load_config(self):
+ self.config = ConfigParser.RawConfigParser()
+
+ # Add defaults
+ self.config.add_section('ScanView')
+ for r in self.reporters:
+ self.config.add_section(r.getName())
+ for p in r.getParameters():
+ if p.saveConfigValue():
+ self.config.set(r.getName(), p.getName(), '')
+
+ # Ignore parse errors
+ try:
+ self.config.read([kConfigPath])
+ except:
+ pass
+
+ # Save on exit
+ import atexit
+ atexit.register(lambda: self.save_config())
+
+ def save_config(self):
+ # Ignore errors (only called on exit).
+ try:
+ f = open(kConfigPath,'w')
+ self.config.write(f)
+ f.close()
+ except:
+ pass
+
+ def halt(self):
+ self.halted = True
+ if self.options.debug:
+ print >>sys.stderr, "%s: SERVER: halting." % (sys.argv[0],)
+
+ def serve_forever(self):
+ while not self.halted:
+ if self.options.debug > 1:
+ print >>sys.stderr, "%s: SERVER: waiting..." % (sys.argv[0],)
+ try:
+ self.handle_request()
+ except OSError,e:
+ print 'OSError',e.errno
+
+ def finish_request(self, request, client_address):
+ if self.options.autoReload:
+ import ScanView
+ self.RequestHandlerClass = reload(ScanView).ScanViewRequestHandler
+ BaseHTTPServer.HTTPServer.finish_request(self, request, client_address)
+
+ def handle_error(self, request, client_address):
+ # Ignore socket errors
+ info = sys.exc_info()
+ if info and isinstance(info[1], socket.error):
+ if self.options.debug > 1:
+ print >>sys.stderr, "%s: SERVER: ignored socket error." % (sys.argv[0],)
+ return
+ BaseHTTPServer.HTTPServer.handle_error(self, request, client_address)
+
+# Borrowed from Quixote, with simplifications.
+def parse_query(qs, fields=None):
+ if fields is None:
+ fields = {}
+ for chunk in filter(None, qs.split('&')):
+ if '=' not in chunk:
+ name = chunk
+ value = ''
+ else:
+ name, value = chunk.split('=', 1)
+ name = urllib.unquote(name.replace('+', ' '))
+ value = urllib.unquote(value.replace('+', ' '))
+ item = fields.get(name)
+ if item is None:
+ fields[name] = [value]
+ else:
+ item.append(value)
+ return fields
+
+class ScanViewRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+ server_version = "ScanViewServer/" + __version__
+ dynamic_mtime = time.time()
+
+ def do_HEAD(self):
+ try:
+ SimpleHTTPServer.SimpleHTTPRequestHandler.do_HEAD(self)
+ except Exception,e:
+ self.handle_exception(e)
+
+ def do_GET(self):
+ try:
+ SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
+ except Exception,e:
+ self.handle_exception(e)
+
+ def do_POST(self):
+ """Serve a POST request."""
+ try:
+ length = self.headers.getheader('content-length') or "0"
+ try:
+ length = int(length)
+ except:
+ length = 0
+ content = self.rfile.read(length)
+ fields = parse_query(content)
+ f = self.send_head(fields)
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
+ except Exception,e:
+ self.handle_exception(e)
+
+ def log_message(self, format, *args):
+ if self.server.options.debug:
+ sys.stderr.write("%s: SERVER: %s - - [%s] %s\n" %
+ (sys.argv[0],
+ self.address_string(),
+ self.log_date_time_string(),
+ format%args))
+
+ def load_report(self, report):
+ path = os.path.join(self.server.root, 'report-%s.html'%report)
+ data = open(path).read()
+ keys = {}
+ for item in kBugKeyValueRE.finditer(data):
+ k,v = item.groups()
+ keys[k] = v
+ return keys
+
+ def load_crashes(self):
+ path = posixpath.join(self.server.root, 'index.html')
+ data = open(path).read()
+ problems = []
+ for item in kReportCrashEntryRE.finditer(data):
+ fieldData = item.group(1)
+ fields = dict([i.groups() for i in
+ kReportCrashEntryKeyValueRE.finditer(fieldData)])
+ problems.append(fields)
+ return problems
+
+ def handle_exception(self, exc):
+ import traceback
+ s = StringIO.StringIO()
+ print >>s, "INTERNAL ERROR\n"
+ traceback.print_exc(exc, s)
+ f = self.send_string(s.getvalue(), 'text/plain')
+ if f:
+ self.copyfile(f, self.wfile)
+ f.close()
+
+ def get_scalar_field(self, name):
+ if name in self.fields:
+ return self.fields[name][0]
+ else:
+ return None
+
+ def submit_bug(self, c):
+ title = self.get_scalar_field('title')
+ description = self.get_scalar_field('description')
+ report = self.get_scalar_field('report')
+ reporterIndex = self.get_scalar_field('reporter')
+ files = []
+ for fileID in self.fields.get('files',[]):
+ try:
+ i = int(fileID)
+ except:
+ i = None
+ if i is None or i<0 or i>=len(c.files):
+ return (False, 'Invalid file ID')
+ files.append(c.files[i])
+
+ if not title:
+ return (False, "Missing title.")
+ if not description:
+ return (False, "Missing description.")
+ try:
+ reporterIndex = int(reporterIndex)
+ except:
+ return (False, "Invalid report method.")
+
+ # Get the reporter and parameters.
+ reporter = self.server.reporters[reporterIndex]
+ parameters = {}
+ for o in reporter.getParameters():
+ name = '%s_%s'%(reporter.getName(),o.getName())
+ if name not in self.fields:
+ return (False,
+ 'Missing field "%s" for %s report method.'%(name,
+ reporter.getName()))
+ parameters[o.getName()] = self.get_scalar_field(name)
+
+ # Update config defaults.
+ if report != 'None':
+ self.server.config.set('ScanView', 'reporter', reporterIndex)
+ for o in reporter.getParameters():
+ if o.saveConfigValue():
+ name = o.getName()
+ self.server.config.set(reporter.getName(), name, parameters[name])
+
+ # Create the report.
+ bug = Reporter.BugReport(title, description, files)
+
+ # Kick off a reporting thread.
+ t = ReporterThread(bug, reporter, parameters, self.server)
+ t.start()
+
+ # Wait for thread to die...
+ while t.isAlive():
+ time.sleep(.25)
+ submitStatus = t.status
+
+ return (t.success, t.status)
+
+ def send_report_submit(self):
+ report = self.get_scalar_field('report')
+ c = self.get_report_context(report)
+ if c.reportSource is None:
+ reportingFor = "Report Crashes > "
+ fileBug = """\
+<a href="/report_crashes">File Bug</a> > """%locals()
+ else:
+ reportingFor = '<a href="/%s">Report %s</a> > ' % (c.reportSource,
+ report)
+ fileBug = '<a href="/report/%s">File Bug</a> > ' % report
+ title = self.get_scalar_field('title')
+ description = self.get_scalar_field('description')
+
+ res,message = self.submit_bug(c)
+
+ if res:
+ statusClass = 'SubmitOk'
+ statusName = 'Succeeded'
+ else:
+ statusClass = 'SubmitFail'
+ statusName = 'Failed'
+
+ result = """
+<head>
+ <title>Bug Submission</title>
+ <link rel="stylesheet" type="text/css" href="/scanview.css" />
+</head>
+<body>
+<h3>
+<a href="/">Summary</a> >
+%(reportingFor)s
+%(fileBug)s
+Submit</h3>
+<form name="form" action="">
+<table class="form">
+<tr><td>
+<table class="form_group">
+<tr>
+ <td class="form_clabel">Title:</td>
+ <td class="form_value">
+ <input type="text" name="title" size="50" value="%(title)s" disabled>
+ </td>
+</tr>
+<tr>
+ <td class="form_label">Description:</td>
+ <td class="form_value">
+<textarea rows="10" cols="80" name="description" disabled>
+%(description)s
+</textarea>
+ </td>
+</table>
+</td></tr>
+</table>
+</form>
+<h1 class="%(statusClass)s">Submission %(statusName)s</h1>
+%(message)s
+<p>
+<hr>
+<a href="/">Return to Summary</a>
+</body>
+</html>"""%locals()
+ return self.send_string(result)
+
+ def send_open_report(self, report):
+ try:
+ keys = self.load_report(report)
+ except IOError:
+ return self.send_error(400, 'Invalid report.')
+
+ file = keys.get('FILE')
+ if not file or not posixpath.exists(file):
+ return self.send_error(400, 'File does not exist: "%s"' % file)
+
+ import startfile
+ if self.server.options.debug:
+ print >>sys.stderr, '%s: SERVER: opening "%s"'%(sys.argv[0],
+ file)
+
+ status = startfile.open(file)
+ if status:
+ res = 'Opened: "%s"' % file
+ else:
+ res = 'Open failed: "%s"' % file
+
+ return self.send_string(res, 'text/plain')
+
+ def get_report_context(self, report):
+ class Context:
+ pass
+ if report is None or report == 'None':
+ data = self.load_crashes()
+ # Don't allow empty reports.
+ if not data:
+ raise ValueError, 'No crashes detected!'
+ c = Context()
+ c.title = 'clang static analyzer failures'
+
+ stderrSummary = ""
+ for item in data:
+ if 'stderr' in item:
+ path = posixpath.join(self.server.root, item['stderr'])
+ if os.path.exists(path):
+ lns = itertools.islice(open(path), 0, 10)
+ stderrSummary += '%s\n--\n%s' % (item.get('src',
+ '<unknown>'),
+ ''.join(lns))
+
+ c.description = """\
+The clang static analyzer failed on these inputs:
+%s
+
+STDERR Summary
+--------------
+%s
+""" % ('\n'.join([item.get('src','<unknown>') for item in data]),
+ stderrSummary)
+ c.reportSource = None
+ c.navMarkup = "Report Crashes > "
+ c.files = []
+ for item in data:
+ c.files.append(item.get('src',''))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('file','')))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('clangfile','')))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('stderr','')))
+ c.files.append(posixpath.join(self.server.root,
+ item.get('info','')))
+ # Just in case something failed, ignore files which don't
+ # exist.
+ c.files = [f for f in c.files
+ if os.path.exists(f) and os.path.isfile(f)]
+ else:
+ # Check that this is a valid report.
+ path = posixpath.join(self.server.root, 'report-%s.html' % report)
+ if not posixpath.exists(path):
+ raise ValueError, 'Invalid report ID'
+ keys = self.load_report(report)
+ c = Context()
+ c.title = keys.get('DESC','clang error (unrecognized')
+ c.description = """\
+Bug reported by the clang static analyzer.
+
+Description: %s
+File: %s
+Line: %s
+"""%(c.title, keys.get('FILE','<unknown>'), keys.get('LINE', '<unknown>'))
+ c.reportSource = 'report-%s.html' % report
+ c.navMarkup = """<a href="/%s">Report %s</a> > """ % (c.reportSource,
+ report)
+
+ c.files = [path]
+ return c
+
+ def send_report(self, report, configOverrides=None):
+ def getConfigOption(section, field):
+ if (configOverrides is not None and
+ section in configOverrides and
+ field in configOverrides[section]):
+ return configOverrides[section][field]
+ return self.server.config.get(section, field)
+
+ # report is None is used for crashes
+ try:
+ c = self.get_report_context(report)
+ except ValueError, e:
+ return self.send_error(400, e.message)
+
+ title = c.title
+ description= c.description
+ reportingFor = c.navMarkup
+ if c.reportSource is None:
+ extraIFrame = ""
+ else:
+ extraIFrame = """\
+<iframe src="/%s" width="100%%" height="40%%"
+ scrolling="auto" frameborder="1">
+ <a href="/%s">View Bug Report</a>
+</iframe>""" % (c.reportSource, c.reportSource)
+
+ reporterSelections = []
+ reporterOptions = []
+
+ try:
+ active = int(getConfigOption('ScanView','reporter'))
+ except:
+ active = 0
+ for i,r in enumerate(self.server.reporters):
+ selected = (i == active)
+ if selected:
+ selectedStr = ' selected'
+ else:
+ selectedStr = ''
+ reporterSelections.append('<option value="%d"%s>%s</option>'%(i,selectedStr,r.getName()))
+ options = '\n'.join([ o.getHTML(r,title,getConfigOption) for o in r.getParameters()])
+ display = ('none','')[selected]
+ reporterOptions.append("""\
+<tr id="%sReporterOptions" style="display:%s">
+ <td class="form_label">%s Options</td>
+ <td class="form_value">
+ <table class="form_inner_group">
+%s
+ </table>
+ </td>
+</tr>
+"""%(r.getName(),display,r.getName(),options))
+ reporterSelections = '\n'.join(reporterSelections)
+ reporterOptionsDivs = '\n'.join(reporterOptions)
+ reportersArray = '[%s]'%(','.join([`r.getName()` for r in self.server.reporters]))
+
+ if c.files:
+ fieldSize = min(5, len(c.files))
+ attachFileOptions = '\n'.join(["""\
+<option value="%d" selected>%s</option>""" % (i,v) for i,v in enumerate(c.files)])
+ attachFileRow = """\
+<tr>
+ <td class="form_label">Attach:</td>
+ <td class="form_value">
+<select style="width:100%%" name="files" multiple size=%d>
+%s
+</select>
+ </td>
+</tr>
+""" % (min(5, len(c.files)), attachFileOptions)
+ else:
+ attachFileRow = ""
+
+ result = """<html>
+<head>
+ <title>File Bug</title>
+ <link rel="stylesheet" type="text/css" href="/scanview.css" />
+</head>
+<script language="javascript" type="text/javascript">
+var reporters = %(reportersArray)s;
+function updateReporterOptions() {
+ index = document.getElementById('reporter').selectedIndex;
+ for (var i=0; i < reporters.length; ++i) {
+ o = document.getElementById(reporters[i] + "ReporterOptions");
+ if (i == index) {
+ o.style.display = "";
+ } else {
+ o.style.display = "none";
+ }
+ }
+}
+</script>
+<body onLoad="updateReporterOptions()">
+<h3>
+<a href="/">Summary</a> >
+%(reportingFor)s
+File Bug</h3>
+<form name="form" action="/report_submit" method="post">
+<input type="hidden" name="report" value="%(report)s">
+
+<table class="form">
+<tr><td>
+<table class="form_group">
+<tr>
+ <td class="form_clabel">Title:</td>
+ <td class="form_value">
+ <input type="text" name="title" size="50" value="%(title)s">
+ </td>
+</tr>
+<tr>
+ <td class="form_label">Description:</td>
+ <td class="form_value">
+<textarea rows="10" cols="80" name="description">
+%(description)s
+</textarea>
+ </td>
+</tr>
+
+%(attachFileRow)s
+
+</table>
+<br>
+<table class="form_group">
+<tr>
+ <td class="form_clabel">Method:</td>
+ <td class="form_value">
+ <select id="reporter" name="reporter" onChange="updateReporterOptions()">
+ %(reporterSelections)s
+ </select>
+ </td>
+</tr>
+%(reporterOptionsDivs)s
+</table>
+<br>
+</td></tr>
+<tr><td class="form_submit">
+ <input align="right" type="submit" name="Submit" value="Submit">
+</td></tr>
+</table>
+</form>
+
+%(extraIFrame)s
+
+</body>
+</html>"""%locals()
+
+ return self.send_string(result)
+
+ def send_head(self, fields=None):
+ if (self.server.options.onlyServeLocal and
+ self.client_address[0] != '127.0.0.1'):
+ return self.send_error(401, 'Unauthorized host.')
+
+ if fields is None:
+ fields = {}
+ self.fields = fields
+
+ o = urlparse.urlparse(self.path)
+ self.fields = parse_query(o.query, fields)
+ path = posixpath.normpath(urllib.unquote(o.path))
+
+ # Split the components and strip the root prefix.
+ components = path.split('/')[1:]
+
+ # Special case some top-level entries.
+ if components:
+ name = components[0]
+ if len(components)==2:
+ if name=='report':
+ return self.send_report(components[1])
+ elif name=='open':
+ return self.send_open_report(components[1])
+ elif len(components)==1:
+ if name=='quit':
+ self.server.halt()
+ return self.send_string('Goodbye.', 'text/plain')
+ elif name=='report_submit':
+ return self.send_report_submit()
+ elif name=='report_crashes':
+ overrides = { 'ScanView' : {},
+ 'Radar' : {},
+ 'Email' : {} }
+ for i,r in enumerate(self.server.reporters):
+ if r.getName() == 'Radar':
+ overrides['ScanView']['reporter'] = i
+ break
+ overrides['Radar']['Component'] = 'llvm - checker'
+ overrides['Radar']['Component Version'] = 'X'
+ return self.send_report(None, overrides)
+ elif name=='favicon.ico':
+ return self.send_path(posixpath.join(kShare,'bugcatcher.ico'))
+
+ # Match directory entries.
+ if components[-1] == '':
+ components[-1] = 'index.html'
+
+ relpath = '/'.join(components)
+ path = posixpath.join(self.server.root, relpath)
+
+ if self.server.options.debug > 1:
+ print >>sys.stderr, '%s: SERVER: sending path "%s"'%(sys.argv[0],
+ path)
+ return self.send_path(path)
+
+ def send_404(self):
+ self.send_error(404, "File not found")
+ return None
+
+ def send_path(self, path):
+ # If the requested path is outside the root directory, do not open it
+ rel = os.path.abspath(path)
+ if not rel.startswith(os.path.abspath(self.server.root)):
+ return self.send_404()
+
+ ctype = self.guess_type(path)
+ if ctype.startswith('text/'):
+ # Patch file instead
+ return self.send_patched_file(path, ctype)
+ else:
+ mode = 'rb'
+ try:
+ f = open(path, mode)
+ except IOError:
+ return self.send_404()
+ return self.send_file(f, ctype)
+
+ def send_file(self, f, ctype):
+ # Patch files to add links, but skip binary files.
+ self.send_response(200)
+ self.send_header("Content-type", ctype)
+ fs = os.fstat(f.fileno())
+ self.send_header("Content-Length", str(fs[6]))
+ self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
+ self.end_headers()
+ return f
+
+ def send_string(self, s, ctype='text/html', headers=True, mtime=None):
+ if headers:
+ self.send_response(200)
+ self.send_header("Content-type", ctype)
+ self.send_header("Content-Length", str(len(s)))
+ if mtime is None:
+ mtime = self.dynamic_mtime
+ self.send_header("Last-Modified", self.date_time_string(mtime))
+ self.end_headers()
+ return StringIO.StringIO(s)
+
+ def send_patched_file(self, path, ctype):
+ # Allow a very limited set of variables. This is pretty gross.
+ variables = {}
+ variables['report'] = ''
+ m = kReportFileRE.match(path)
+ if m:
+ variables['report'] = m.group(2)
+
+ try:
+ f = open(path,'r')
+ except IOError:
+ return self.send_404()
+ fs = os.fstat(f.fileno())
+ data = f.read()
+ for a,b in kReportReplacements:
+ data = a.sub(b % variables, data)
+ return self.send_string(data, ctype, mtime=fs.st_mtime)
+
+
+def create_server(address, options, root):
+ import Reporter
+
+ reporters = Reporter.getReporters()
+
+ return ScanViewServer(address, ScanViewRequestHandler,
+ root,
+ reporters,
+ options)
diff --git a/linux-x64/clang/share/scan-view/bugcatcher.ico b/linux-x64/clang/share/scan-view/bugcatcher.ico
new file mode 100644
index 0000000..22d39b5
--- /dev/null
+++ b/linux-x64/clang/share/scan-view/bugcatcher.ico
Binary files differ
diff --git a/linux-x64/clang/share/scan-view/startfile.py b/linux-x64/clang/share/scan-view/startfile.py
new file mode 100644
index 0000000..6739359
--- /dev/null
+++ b/linux-x64/clang/share/scan-view/startfile.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""Utility for opening a file using the default application in a cross-platform
+manner. Modified from http://code.activestate.com/recipes/511443/.
+"""
+
+__version__ = '1.1x'
+__all__ = ['open']
+
+import os
+import sys
+import webbrowser
+import subprocess
+
+_controllers = {}
+_open = None
+
+
+class BaseController(object):
+ '''Base class for open program controllers.'''
+
+ def __init__(self, name):
+ self.name = name
+
+ def open(self, filename):
+ raise NotImplementedError
+
+
+class Controller(BaseController):
+ '''Controller for a generic open program.'''
+
+ def __init__(self, *args):
+ super(Controller, self).__init__(os.path.basename(args[0]))
+ self.args = list(args)
+
+ def _invoke(self, cmdline):
+ if sys.platform[:3] == 'win':
+ closefds = False
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ else:
+ closefds = True
+ startupinfo = None
+
+ if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or
+ sys.platform == 'darwin'):
+ inout = file(os.devnull, 'r+')
+ else:
+ # for TTY programs, we need stdin/out
+ inout = None
+
+ # if possible, put the child precess in separate process group,
+ # so keyboard interrupts don't affect child precess as well as
+ # Python
+ setsid = getattr(os, 'setsid', None)
+ if not setsid:
+ setsid = getattr(os, 'setpgrp', None)
+
+ pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
+ stderr=inout, close_fds=closefds,
+ preexec_fn=setsid, startupinfo=startupinfo)
+
+ # It is assumed that this kind of tools (gnome-open, kfmclient,
+ # exo-open, xdg-open and open for OSX) immediately exit after lauching
+ # the specific application
+ returncode = pipe.wait()
+ if hasattr(self, 'fixreturncode'):
+ returncode = self.fixreturncode(returncode)
+ return not returncode
+
+ def open(self, filename):
+ if isinstance(filename, basestring):
+ cmdline = self.args + [filename]
+ else:
+ # assume it is a sequence
+ cmdline = self.args + filename
+ try:
+ return self._invoke(cmdline)
+ except OSError:
+ return False
+
+
+# Platform support for Windows
+if sys.platform[:3] == 'win':
+
+ class Start(BaseController):
+ '''Controller for the win32 start progam through os.startfile.'''
+
+ def open(self, filename):
+ try:
+ os.startfile(filename)
+ except WindowsError:
+ # [Error 22] No application is associated with the specified
+ # file for this operation: '<URL>'
+ return False
+ else:
+ return True
+
+ _controllers['windows-default'] = Start('start')
+ _open = _controllers['windows-default'].open
+
+
+# Platform support for MacOS
+elif sys.platform == 'darwin':
+ _controllers['open']= Controller('open')
+ _open = _controllers['open'].open
+
+
+# Platform support for Unix
+else:
+
+ import commands
+
+ # @WARNING: use the private API of the webbrowser module
+ from webbrowser import _iscommand
+
+ class KfmClient(Controller):
+ '''Controller for the KDE kfmclient program.'''
+
+ def __init__(self, kfmclient='kfmclient'):
+ super(KfmClient, self).__init__(kfmclient, 'exec')
+ self.kde_version = self.detect_kde_version()
+
+ def detect_kde_version(self):
+ kde_version = None
+ try:
+ info = commands.getoutput('kde-config --version')
+
+ for line in info.splitlines():
+ if line.startswith('KDE'):
+ kde_version = line.split(':')[-1].strip()
+ break
+ except (OSError, RuntimeError):
+ pass
+
+ return kde_version
+
+ def fixreturncode(self, returncode):
+ if returncode is not None and self.kde_version > '3.5.4':
+ return returncode
+ else:
+ return os.EX_OK
+
+ def detect_desktop_environment():
+ '''Checks for known desktop environments
+
+ Return the desktop environments name, lowercase (kde, gnome, xfce)
+ or "generic"
+
+ '''
+
+ desktop_environment = 'generic'
+
+ if os.environ.get('KDE_FULL_SESSION') == 'true':
+ desktop_environment = 'kde'
+ elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
+ desktop_environment = 'gnome'
+ else:
+ try:
+ info = commands.getoutput('xprop -root _DT_SAVE_MODE')
+ if ' = "xfce4"' in info:
+ desktop_environment = 'xfce'
+ except (OSError, RuntimeError):
+ pass
+
+ return desktop_environment
+
+
+ def register_X_controllers():
+ if _iscommand('kfmclient'):
+ _controllers['kde-open'] = KfmClient()
+
+ for command in ('gnome-open', 'exo-open', 'xdg-open'):
+ if _iscommand(command):
+ _controllers[command] = Controller(command)
+
+ def get():
+ controllers_map = {
+ 'gnome': 'gnome-open',
+ 'kde': 'kde-open',
+ 'xfce': 'exo-open',
+ }
+
+ desktop_environment = detect_desktop_environment()
+
+ try:
+ controller_name = controllers_map[desktop_environment]
+ return _controllers[controller_name].open
+
+ except KeyError:
+ if _controllers.has_key('xdg-open'):
+ return _controllers['xdg-open'].open
+ else:
+ return webbrowser.open
+
+
+ if os.environ.get("DISPLAY"):
+ register_X_controllers()
+ _open = get()
+
+
+def open(filename):
+ '''Open a file or an URL in the registered default application.'''
+
+ return _open(filename)