bin/find-unneeded-includes                |  233 ++++++++++++++++++++++++++++++
 sc/IwyuFilter_sc.yaml                     |    2 
 sw/IwyuFilter_sw.yaml                     |   64 ++++++++
 writerfilter/IwyuFilter_writerfilter.yaml |    8 +
 4 files changed, 307 insertions(+)

New commits:
commit b5ede834dece9e5ece3e525f610912984c60661b
Author: Miklos Vajna <vmik...@collabora.co.uk>
Date:   Tue Apr 3 09:20:57 2018 +0200

    Add IWYU wrapper script to find unused includes
    
    I've used this script in the recent past to fix warnings in mostly
    sw/inc/*.hxx. Hopefully sharing it creates interest for others to do
    similar fixes in other modules.
    
    Change-Id: I4c8b6a1e92b006d4fd56b403a25715f11964d639
    Reviewed-on: https://gerrit.libreoffice.org/52289
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Michael Stahl <michael.st...@cib.de>

diff --git a/bin/find-unneeded-includes b/bin/find-unneeded-includes
new file mode 100755
index 000000000000..9723ceffbfb9
--- /dev/null
+++ b/bin/find-unneeded-includes
@@ -0,0 +1,233 @@
+#!/usr/bin/env python3
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This parses the output of 'include-what-you-use', focusing on just removing
+# not needed includes and providing a relatively conservative output by
+# filtering out a number of LibreOffice-specific false positives.
+#
+# It assumes you have a 'compile_commands.json' around (similar to clang-tidy),
+# you can generate one with 'make vim-ide-integration'.
+#
+# Design goals:
+# - blacklist mechanism, so a warning is either fixed or blacklisted
+# - works in a plugins-enabled clang build
+# - no custom configure options required
+# - no need to generate a dummy library to build a header
+
+import glob
+import json
+import multiprocessing
+import os
+import queue
+import re
+import subprocess
+import sys
+import threading
+import yaml
+
+
+def ignoreRemoval(include, toAdd, absFileName, moduleRules):
+    # global rules
+
+    # Avoid replacing .hpp with .hdl in the com::sun::star namespace.
+    if include.startswith("com/sun/star") and include.endswith(".hpp"):
+        hdl = include.replace(".hpp", ".hdl")
+        if hdl in toAdd:
+            return True
+
+    # Avoid debug STL.
+    debugStl = {
+        "array": "debug/array",
+        "deque": "debug/deque",
+        "list": "debug/list",
+        "map": "debug/map.h",
+        "set": "debug/set.h",
+        "unordered_map": "debug/unordered_map",
+        "unordered_set": "debug/unordered_set",
+        "vector": "debug/vector",
+    }
+    for k, v in debugStl.items():
+        if include == k and v in toAdd:
+            return True
+
+    # Follow boost documentation.
+    if include == "boost/optional.hpp" and "boost/optional/optional.hpp" in 
toAdd:
+        return True
+    if include == "boost/intrusive_ptr.hpp" and 
"boost/smart_ptr/intrusive_ptr.hpp" in toAdd:
+        return True
+
+    # 3rd-party, non-self-contained headers.
+    if include == "libepubgen/libepubgen.h" and 
"libepubgen/libepubgen-decls.h" in toAdd:
+        return True
+    if include == "librevenge/librevenge.h" and 
"librevenge/RVNGPropertyList.h" in toAdd:
+        return True
+
+    noRemove = (
+        # <https://www.openoffice.org/tools/CodingGuidelines.sxw> insists on 
not
+        # removing this.
+        "sal/config.h",
+        # Works around a build breakage specific to the broken Android
+        # toolchain.
+        "android/compatibility.hxx",
+    )
+    if include in noRemove:
+        return True
+
+    # Ignore when <foo> is to be replaced with "foo".
+    if include in toAdd:
+        return True
+
+    fileName = os.path.relpath(absFileName, os.getcwd())
+
+    # yaml rules
+
+    if "blacklist" in moduleRules.keys():
+        blacklistRules = moduleRules["blacklist"]
+        if fileName in blacklistRules.keys():
+            if include in blacklistRules[fileName]:
+                return True
+
+    return False
+
+
+def unwrapInclude(include):
+    # Drop <> or "" around the include.
+    return include[1:-1]
+
+
+def processIWYUOutput(iwyuOutput, moduleRules):
+    inAdd = False
+    toAdd = []
+    inRemove = False
+    toRemove = []
+    currentFileName = None
+    for line in iwyuOutput:
+        line = line.strip()
+
+        if len(line) == 0:
+            if inRemove:
+                inRemove = False
+                continue
+            if inAdd:
+                inAdd = False
+                continue
+
+        match = re.match("(.*) should add these lines:$", line)
+        if match:
+            currrentFileName = match.group(1)
+            inAdd = True
+            continue
+
+        match = re.match("(.*) should remove these lines:$", line)
+        if match:
+            currentFileName = match.group(1)
+            inRemove = True
+            continue
+
+        if inAdd:
+            match = re.match('#include ([^ ]+)', line)
+            if match:
+                include = unwrapInclude(match.group(1))
+                toAdd.append(include)
+            else:
+                # Forward declaration.
+                toAdd.append(line)
+
+        if inRemove:
+            match = re.match("- #include (.*)  // lines (.*)-.*", line)
+            if match:
+                include = unwrapInclude(match.group(1))
+                lineno = match.group(2)
+                if not ignoreRemoval(include, toAdd, currentFileName, 
moduleRules):
+                    toRemove.append("%s:%s: %s" % (currentFileName, lineno, 
include))
+                continue
+
+    for remove in toRemove:
+        print("ERROR: %s: remove not needed include" % remove)
+    return len(toRemove)
+
+
+def run_tool(task_queue, failed_files):
+    while True:
+        invocation, moduleRules = task_queue.get()
+        if not len(failed_files):
+            print("[IWYU] " + invocation.split(' ')[-1])
+            p = subprocess.Popen(invocation, shell=True, 
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+            retcode = 
processIWYUOutput(p.communicate()[0].decode('utf-8').splitlines(), moduleRules)
+            if retcode != 0:
+                print("ERROR: '" + invocation + "' found unused includes.")
+                failed_files.append(invocation)
+        task_queue.task_done()
+
+
+def tidy(compileCommands, paths):
+    return_code = 0
+    try:
+        max_task = multiprocessing.cpu_count()
+        task_queue = queue.Queue(max_task)
+        failed_files = []
+        for _ in range(max_task):
+            t = threading.Thread(target=run_tool, args=(task_queue, 
failed_files))
+            t.daemon = True
+            t.start()
+
+        for path in sorted(paths):
+            moduleName = path.split("/")[0]
+
+            rulePath = os.path.join(moduleName, "IwyuFilter_" + moduleName + 
".yaml")
+            moduleRules = {}
+            if os.path.exists(rulePath):
+                moduleRules = yaml.load(open(rulePath))
+            assume = None
+            pathAbs = os.path.abspath(path)
+            compileFile = pathAbs
+            matches = [i for i in compileCommands if i["file"] == compileFile]
+            if not len(matches):
+                if "assumeFilename" in moduleRules.keys():
+                    assume = moduleRules["assumeFilename"]
+                if assume:
+                    assumeAbs = os.path.abspath(assume)
+                    compileFile = assumeAbs
+                    matches = [i for i in compileCommands if i["file"] == 
compileFile]
+                    if not len(matches):
+                        print("WARNING: no compile commands for '" + path + "' 
(assumed filename: '" + assume + "'")
+                        continue
+                else:
+                    print("WARNING: no compile commands for '" + path + "'")
+                    continue
+
+            _, _, args = matches[0]["command"].partition(" ")
+            if assume:
+                args = args.replace(assumeAbs, "-x c++ " + pathAbs)
+
+            invocation = "include-what-you-use " + args
+            task_queue.put((invocation, moduleRules))
+
+        task_queue.join()
+        if len(failed_files):
+            return_code = 1
+
+    except KeyboardInterrupt:
+        print('\nCtrl-C detected, goodbye.')
+        os.kill(0, 9)
+
+    sys.exit(return_code)
+
+
+def main(argv):
+    if not len(argv):
+        print("usage: find-unneeded-includes [FILE]...")
+        return
+
+    with open("compile_commands.json", 'r') as compileCommandsSock:
+        compileCommands = json.load(compileCommandsSock)
+
+    tidy(compileCommands, paths=argv)
+
+if __name__ == '__main__':
+    main(sys.argv[1:])
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sc/IwyuFilter_sc.yaml b/sc/IwyuFilter_sc.yaml
new file mode 100644
index 000000000000..ff22e0e3a659
--- /dev/null
+++ b/sc/IwyuFilter_sc.yaml
@@ -0,0 +1,2 @@
+---
+assumeFilename: sc/source/core/data/document.cxx
diff --git a/sw/IwyuFilter_sw.yaml b/sw/IwyuFilter_sw.yaml
new file mode 100644
index 000000000000..0cd235052705
--- /dev/null
+++ b/sw/IwyuFilter_sw.yaml
@@ -0,0 +1,64 @@
+---
+assumeFilename: sw/source/core/doc/docnew.cxx
+blacklist:
+    sw/inc/extinput.hxx:
+    - vector
+    sw/inc/fmtmeta.hxx:
+    - vector
+    sw/inc/istyleaccess.hxx:
+    - vector
+    sw/inc/shellres.hxx:
+    - memory
+    sw/inc/docary.hxx:
+    # Complete type is needed here:
+    # fldbas.hxx brings in SwTOXType, which is needed by SwTOXTypes, as 
SwVectorModifyBase's dtor wants to delete it
+    - fldbas.hxx
+    # numrule.hxx brings in SwNumRule, which is needed by SwNumRuleTable, as 
SwVectorModifyBase's dtor wants to delete it
+    - numrule.hxx
+    # tox.hxx brings in SwTOXType, which is needed by SwTOXTypes, as 
SwVectorModifyBase's dtor wants to delete it
+    - tox.hxx
+    sw/inc/docfac.hxx:
+    # Complete type is needed by rtl::Reference<SwDoc>.
+    - doc.hxx
+    sw/inc/accmap.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/crsrsh.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/cshtyp.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/fesh.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/modcfg.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/ndtyp.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/swtypes.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/doc.hxx:
+    - o3tl/deleter.hxx
+    sw/inc/list.hxx:
+    - o3tl/deleter.hxx
+    sw/inc/IDocumentLinksAdministration.hxx:
+    - sal/types.h
+    sw/inc/pagedesc.hxx:
+    - boost/multi_index/identity.hpp
+    sw/inc/rdfhelper.hxx:
+    - com/sun/star/uno/Reference.h
+    sw/inc/ring.hxx:
+    - utility
+    sw/inc/shellid.hxx:
+    - sfx2/shell.hxx
+    sw/inc/swurl.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/tblenum.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/tox.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/undobj.hxx:
+    - o3tl/typed_flags_set.hxx
+    sw/inc/unosett.hxx:
+    # sw::UnoImplPtr typedef
+    - unobaseclass.hxx
+    sw/inc/unotxdoc.hxx:
+    # sw::UnoImplPtr typedef
+    - unobaseclass.hxx
diff --git a/writerfilter/IwyuFilter_writerfilter.yaml 
b/writerfilter/IwyuFilter_writerfilter.yaml
new file mode 100644
index 000000000000..1397a6e48f53
--- /dev/null
+++ b/writerfilter/IwyuFilter_writerfilter.yaml
@@ -0,0 +1,8 @@
+---
+assumeFilename: writerfilter/source/filter/WriterFilter.cxx
+blacklist:
+    writerfilter/source/rtftok/rtfsdrimport.hxx:
+    # IWYU assumes std::stack<IncompleteType> in a header is OK, but that's not
+    # the case for all of LO's supported platforms.
+    # See 
<https://github.com/include-what-you-use/include-what-you-use/issues/175>.
+    - dmapper/GraphicZOrderHelper.hxx
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to