#!/usr/bin/env python # #===- run-clang-tidy.py - Parallel clang-tidy runner ---------*- python -*--===# # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # #===------------------------------------------------------------------------===# # 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 try: import yaml except ImportError: yaml = None 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) 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, lock, 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) proc = subprocess.Popen(invocation) proc.wait() if it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "factory.h" #include "log.h" #include "plain.h" #include "anaglyph.h" #include "interlaced.h" #include "pageflip.h" #include "sidebyside.h" RenderingCore *createRenderingCore(const std::string &stereo_mode, IrrlichtDevice *device, Client *client, Hud *hud) { if (stereo_mode == "none") return new RenderingCorePlain(device, client, hud); if (stereo_mode == "anaglyph") return new RenderingCoreAnaglyph(device, client, hud); if (stereo_mode == "interlaced") return new RenderingCoreInterlaced(device, client, hud); #ifdef STEREO_PAGEFLIP_SUPPORTED if (stereo_mode == "pageflip") return new RenderingCorePageflip(device, client, hud); #endif if (stereo_mode == "sidebyside") return new RenderingCoreSideBySide(device, client, hud); if (stereo_mode == "topbottom") return new RenderingCoreSideBySide(device, client, hud, true); if (stereo_mode == "crossview") return new RenderingCoreSideBySide(device, client, hud, false, true); // fallback to plain renderer errorstream << "Invalid rendering mode: " << stereo_mode << std::endl; return new RenderingCorePlain(device, client,<