diff options
author | Yabin Cui <yabinc@google.com> | 2020-04-29 10:54:45 -0700 |
---|---|---|
committer | Yabin Cui <yabinc@google.com> | 2020-04-29 10:54:45 -0700 |
commit | f71cc7fa68ac644595257d6fdebc2e543cb7041c (patch) | |
tree | 81eef62411c6d9a4c89870cc811173f0c7bed2c3 /clang-r383902/share/clang/clang-include-fixer.py | |
parent | 27fa4eeb5967e0bae5aef6de643739bef2a58726 (diff) | |
download | prebuilts_clang_host_linux-x86-f71cc7fa68ac644595257d6fdebc2e543cb7041c.tar.gz prebuilts_clang_host_linux-x86-f71cc7fa68ac644595257d6fdebc2e543cb7041c.tar.bz2 prebuilts_clang_host_linux-x86-f71cc7fa68ac644595257d6fdebc2e543cb7041c.zip |
Update prebuilt Clang to r383902.
clang 11.0.1 (based on r383902) from build 6443078.
Bug: http://b/149839606
Test: N/A
Change-Id: Id966d7b2cbaf3d2711a1e528c41a173ae28f6c11
Diffstat (limited to 'clang-r383902/share/clang/clang-include-fixer.py')
-rwxr-xr-x | clang-r383902/share/clang/clang-include-fixer.py | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/clang-r383902/share/clang/clang-include-fixer.py b/clang-r383902/share/clang/clang-include-fixer.py new file mode 100755 index 00000000..e3a52f09 --- /dev/null +++ b/clang-r383902/share/clang/clang-include-fixer.py @@ -0,0 +1,219 @@ +# 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/clang-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/clang-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. + +from __future__ import print_function +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 clang-include-fixer run. + print("Invalid option: {}".format(res), file=sys.stderr) + return GetUserSelection(message, headers, maximum_suggested_headers) + return headers[idx - 1] + + +def execute(command, text): + # Avoid flashing a cmd prompt on Windows. + startupinfo = None + if sys.platform.startswith('win32'): + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + startupinfo.wShowWindow = subprocess.SW_HIDE + + p = subprocess.Popen(command, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + stdin=subprocess.PIPE, startupinfo=startupinfo) + return p.communicate(input=text.encode('utf-8')) + + +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("Error while running clang-include-fixer: {}".format(stderr), + file=sys.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 clang-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(error, file=sys.stderr) + return + + +if __name__ == '__main__': + main() |