summaryrefslogtreecommitdiffstats
path: root/bin/find-unused-defines.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/find-unused-defines.py')
-rwxr-xr-xbin/find-unused-defines.py178
1 files changed, 178 insertions, 0 deletions
diff --git a/bin/find-unused-defines.py b/bin/find-unused-defines.py
new file mode 100755
index 000000000..53db9d1d5
--- /dev/null
+++ b/bin/find-unused-defines.py
@@ -0,0 +1,178 @@
+#!/usr/bin/python3
+
+# Search for unused constants in header files.
+#
+# Note that sometimes these constants are calculated, so some careful checking of the output is necessary.
+#
+# Takes about 4 hours to run this on a fast machine with an SSD
+#
+
+import subprocess
+import sys
+import re
+
+exclusionSet = set([
+ # List of RID constants where we compute a value using a base before calling one of the RESSTR methods
+ # Found with: git grep -P 'RID_\w+\s*\+' -- :/ ':!*.hrc' ':!*.src' ':!*.java' ':!*.py' ':!*.xba'
+ "RID_SVXSTR_KEY_",
+ "RID_UPDATE_BUBBLE_TEXT_",
+ "RID_UPDATE_BUBBLE_T_TEXT_",
+ "RID_SVXSTR_TBLAFMT_",
+ "RID_BMP_CONTENT_",
+ "RID_DROPMODE_",
+ "RID_BMP_LEVEL",
+ "RID_SVXSTR_BULLET_DESCRIPTION",
+ "RID_SVXSTR_SINGLENUM_DESCRIPTION",
+ "RID_SVXSTR_OUTLINENUM_DESCRIPTION",
+ "RID_SVXSTR_RULER_",
+ "RID_GALLERYSTR_THEME_",
+ "RID_SVXSTR_BULLET_DESCRIPTION",
+ "RID_SVXSTR_SINGLENUM_DESCRIPTION",
+ "RID_SVXSTR_OUTLINENUM_DESCRIPTION",
+ # doing some weird stuff in svx/source/unodraw/unoprov.cxx involving mapping of UNO api names to translated names and back again
+ "RID_SVXSTR_GRDT",
+ "RID_SVXSTR_HATCH",
+ "RID_SVXSTR_BMP",
+ "RID_SVXSTR_DASH",
+ "RID_SVXSTR_LEND",
+ "RID_SVXSTR_TRASNGR",
+ # other places doing calculations
+ "RID_SVXSTR_DEPTH",
+ "RID_SUBSETSTR_",
+ "ANALYSIS_",
+ "FLD_DOCINFO_CHANGE",
+ "FLD_EU_",
+ "FLD_INPUT_",
+ "FLD_PAGEREF_",
+ "FLD_STAT_",
+ "FMT_AUTHOR_",
+ "FMT_CHAPTER_",
+ "FMT_DBFLD_",
+ "FMT_FF_",
+ "FMT_GETVAR_",
+ "FMT_MARK_",
+ "FMT_REF_",
+ "FMT_SETVAR_",
+ "STR_AUTH_FIELD_ADDRESS_",
+ "STR_AUTH_TYPE_",
+ "STR_AUTOFMTREDL_",
+ "STR_CONTENT_TYPE_",
+ "STR_UPDATE_ALL",
+ "STR_UPDATE_INDEX",
+ "STR_UPDATE_LINK",
+ "BMP_PLACEHOLDER_",
+ "STR_RPT_HELP_",
+ "STR_TEMPLATE_NAME",
+ "UID_BRWEVT_",
+ "HID_EVT_",
+ "HID_PROP_",
+ "STR_VOBJ_MODE_",
+ "STR_COND_",
+ "SCSTR_CONTENT_",
+ "DATE_FUNCDESC_",
+ "DATE_FUNCNAME_",
+ "DATE_DEFFUNCNAME_",
+ "PRICING_DEFFUNCNAME_",
+ "PRICING_FUNCDESC_",
+ "PRICING_FUNCNAME_",
+ "STR_ItemValCAPTION",
+ "STR_ItemValCIRC",
+ "STR_ItemValEDGE",
+ "STR_ItemValFITTOSIZE",
+ "STR_ItemValMEASURE_",
+ "STR_ItemValMEASURETEXT_",
+ "STR_ItemValTEXTANI_",
+ "STR_ItemValTEXTHADJ",
+ "STR_ItemValTEXTVADJ",
+ "RID_SVXITEMS_VERJUST",
+ "RID_SVXITEMS_ORI",
+ "RID_SVXITEMS_JUSTMETHOD",
+ "RID_SVXITEMS_HORJUST",
+ "MM_PART",
+ ])
+
+
+def in_exclusion_set( a ):
+ for f in exclusionSet:
+ if a.startswith(f):
+ return True;
+ return False;
+
+
+# Hack to turn off unicode decoding errors, which sometimes happens in the output and I really don't
+# care
+import codecs
+def strict_handler(exception):
+ return u"", exception.end
+codecs.register_error("strict", strict_handler)
+
+# find defines, excluding the externals folder
+a = subprocess.Popen("git grep -hP '^#define\\s+\\w\\w\\w\\w+\\s*' -- \"[!e][!x][!t]*\" | sort -u", stdout=subprocess.PIPE, shell=True, encoding='UTF-8')
+
+name_re = re.compile(r"#define\s+(\w+)")
+with a.stdout as txt:
+ for line in txt:
+ idName = name_re.match(str(line)).group(1)
+ if idName.startswith("INCLUDED_"): continue
+ # the various _START and _END constants are normally unused outside of the .hrc and .src files, and that's fine
+ if idName.endswith("_START"): continue
+ if idName.endswith("_BEGIN"): continue
+ if idName.endswith("_END"): continue
+ if idName == "RID_SVX_FIRSTFREE": continue
+ if idName == "": continue
+ if idName.startswith("__com"): continue # these are the include/header macros for the UNO stuff
+ if in_exclusion_set(idName): continue
+ # search for the constant
+ b = subprocess.Popen(["git", "grep", "-w", idName], stdout=subprocess.PIPE, encoding='UTF-8')
+ found_reason_to_exclude = False
+ with b.stdout as txt2:
+ cnt = 0
+ for line2 in txt2:
+ line2 = line2.strip() # otherwise the comparisons below will not work
+ # ignore if/undef magic, does not indicate an actual use (most of the time)
+ if "ifdef" in line2: continue
+ if "undef" in line2: continue
+ # ignore commented out code
+ if line2.startswith("//"): continue
+ if line2.startswith("/*"): continue
+ # check if we found one in actual code
+ if idName.startswith("SID_"):
+ if not ".hrc:" in line2 and not ".src:" in line2 and not ".sdi:" in line2: found_reason_to_exclude = True
+ else:
+ if not ".hrc:" in line2 and not ".src:" in line2: found_reason_to_exclude = True
+ if idName.startswith("RID_"):
+ # is the constant being used as an identifier by entries in .src files?
+ if ".src:" in line2 and "Identifier = " in line2: found_reason_to_exclude = True
+ # is the constant being used by the property controller extension or reportdesigner inspection,
+ # which use macros to declare constants, hiding them from a search
+ if "extensions/source/propctrlr" in line2: found_reason_to_exclude = True
+ if "reportdesign/source/ui/inspection/inspection.src" in line2: found_reason_to_exclude = True
+ if idName.startswith("HID_"):
+ # is the constant being used as an identifier by entries in .src files
+ if ".src:" in line2 and "HelpId = " in line2: found_reason_to_exclude = True
+ # is it being used as a constant in an ItemList in .src files?
+ if ".src:" in line2 and (";> ;" in line2 or "; >;" in line2): found_reason_to_exclude = True
+ # these are used in calculations in other .hrc files
+ if "sw/inc/rcid.hrc:" in line2: found_reason_to_exclude = True
+ # calculations
+ if "sw/source/uibase/inc/ribbar.hrc:" in line2 and "ST_" in idName: found_reason_to_exclude = True
+ if "sw/source/uibase/inc/ribbar.hrc:" in line2 and "STR_IMGBTN_" in idName: found_reason_to_exclude = True
+ if "sw/source/core/undo/undo.hrc:" in line2: found_reason_to_exclude = True
+ if "sw/inc/poolfmt.hrc:" in line2: found_reason_to_exclude = True
+ # used via a macro that hides them from search
+ if "dbaccess/" in line2 and idName.startswith("PROPERTY_ID_"): found_reason_to_exclude = True
+ if "reportdesign/" in line2 and idName.startswith("HID_RPT_PROP_"): found_reason_to_exclude = True
+ if "reportdesign/" in line2 and idName.startswith("RID_STR_"): found_reason_to_exclude = True
+ if "forms/" in line2 and idName.startswith("PROPERTY_"): found_reason_to_exclude = True
+ if "svx/source/tbxctrls/extrusioncontrols.hrc:" in line2 and idName.startswith("DIRECTION_"): found_reason_to_exclude = True
+ if "svx/source/tbxctrls/extrusioncontrols.hrc:" in line2 and idName.startswith("FROM_"): found_reason_to_exclude = True
+ # if we see more than a few lines then it's probably one of the BASE/START/BEGIN things
+ cnt = cnt + 1
+ if cnt > 2: found_reason_to_exclude = True
+ if not found_reason_to_exclude:
+ print(idName)
+ # otherwise the previous line of output will be incorrectly mixed into the below git output, because of buffering
+ sys.stdout.flush()
+ # search again, so we log the location and filename of stuff we want to remove
+ subprocess.call(["git", "grep", "-wn", idName])
+