Merge "Remove WITH_SYNTAX_CHECK"
diff --git a/core/clang/tidy.mk b/core/clang/tidy.mk
index 7ec9378..c1d485d 100644
--- a/core/clang/tidy.mk
+++ b/core/clang/tidy.mk
@@ -78,6 +78,7 @@
# Do not give warnings to external or vendor header files,
# which contain too many warnings.
DEFAULT_TIDY_HEADER_DIRS := \
+ $(subst $(space),, \
art/ \
|bionic/ \
|bootable/ \
@@ -89,7 +90,8 @@
|frameworks/ \
|libcore/ \
|libnativehelper/ \
- |system/
+ |system/ \
+ )
# Default filter contains current directory $1 and DEFAULT_TIDY_HEADER_DIRS.
define default_tidy_header_filter
diff --git a/core/clear_vars.mk b/core/clear_vars.mk
index dfa497e..6614489 100644
--- a/core/clear_vars.mk
+++ b/core/clear_vars.mk
@@ -196,6 +196,7 @@
LOCAL_DPI_FILE_STEM:=
LOCAL_SANITIZE:=
LOCAL_SANITIZE_RECOVER:=
+LOCAL_SANITIZE_DIAG:=
LOCAL_NOSANITIZE:=
LOCAL_DATA_BINDING:=
LOCAL_DBUS_PROXY_PREFIX:=
diff --git a/core/config_sanitizers.mk b/core/config_sanitizers.mk
index ac3e4fc..2e14fef 100644
--- a/core/config_sanitizers.mk
+++ b/core/config_sanitizers.mk
@@ -133,6 +133,11 @@
endif
endif
+ifneq ($(filter cfi,$(my_sanitize)),)
+ my_cflags += -flto -fsanitize-cfi-cross-dso -fvisibility=default
+ my_ldflags += -flto -fsanitize-cfi-cross-dso -fsanitize=cfi -Wl,-plugin-opt,O1 -Wl,-export-dynamic-symbol=__cfi_check
+endif
+
# If local or global modules need ASAN, add linker flags.
ifneq ($(filter address,$(my_global_sanitize) $(my_sanitize)),)
my_ldflags += $(ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS)
@@ -187,3 +192,13 @@
recover_arg := $(subst $(space),$(comma),$(LOCAL_SANITIZE_RECOVER)),
my_cflags += -fsanitize-recover=$(recover_arg)
endif
+
+ifneq ($(strip $(LOCAL_SANITIZE_DIAG)),)
+ notrap_arg := $(subst $(space),$(comma),$(LOCAL_SANITIZE_DIAG)),
+ my_cflags += -fno-sanitize-trap=$(notrap_arg)
+ # Diagnostic requires a runtime library, unless ASan or TSan are also enabled.
+ ifeq ($(filter address thread,$(my_sanitize)),)
+ # Does not have to be the first DT_NEEDED unlike ASan.
+ my_shared_libraries += $($(LOCAL_2ND_ARCH_VAR_PREFIX)UBSAN_RUNTIME_LIBRARY)
+ endif
+endif
diff --git a/target/product/embedded.mk b/target/product/embedded.mk
index 55de3b9..5faf24f 100644
--- a/target/product/embedded.mk
+++ b/target/product/embedded.mk
@@ -32,6 +32,7 @@
grep \
gzip \
healthd \
+ hwservicemanager \
init \
init.environ.rc \
init.rc \
diff --git a/tools/warn.py b/tools/warn.py
index d8dbd1c..7d9ba65 100755
--- a/tools/warn.py
+++ b/tools/warn.py
@@ -1,17 +1,95 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# This file uses the following encoding: utf-8
+"""Grep warnings messages and output HTML tables or warning counts in CSV.
+
+Default is to output warnings in HTML tables grouped by warning severity.
+Use option --byproject to output tables grouped by source file projects.
+Use option --gencsv to output warning counts in CSV format.
+"""
+
+# List of important data structures and functions in this script.
+#
+# To parse and keep warning message in the input file:
+# severity: classification of message severity
+# severity.range [0, 1, ... last_severity_level]
+# severity.colors for header background
+# severity.column_headers for the warning count table
+# severity.headers for warning message tables
+# warn_patterns:
+# warn_patterns[w]['category'] tool that issued the warning, not used now
+# warn_patterns[w]['description'] table heading
+# warn_patterns[w]['members'] matched warnings from input
+# warn_patterns[w]['option'] compiler flag to control the warning
+# warn_patterns[w]['patterns'] regular expressions to match warnings
+# warn_patterns[w]['projects'][p] number of warnings of pattern w in p
+# warn_patterns[w]['severity'] severity level
+# project_list[p][0] project name
+# project_list[p][1] regular expression to match a project path
+# project_patterns[p] re.compile(project_list[p][1])
+# project_names[p] project_list[p][0]
+# warning_messages array of each warning message, without source url
+# warning_records array of [idx to warn_patterns,
+# idx to project_names,
+# idx to warning_messages]
+# platform_version
+# target_product
+# target_variant
+# compile_patterns, parse_input_file
+#
+# To emit html page of warning messages:
+# flags: --byproject, --url, --separator
+# Old stuff for static html components:
+# html_script_style: static html scripts and styles
+# htmlbig:
+# dump_stats, dump_html_prologue, dump_html_epilogue:
+# emit_buttons:
+# dump_fixed
+# sort_warnings:
+# emit_stats_by_project:
+# all_patterns,
+# findproject, classify_warning
+# dump_html
+#
+# New dynamic HTML page's static JavaScript data:
+# Some data are copied from Python to JavaScript, to generate HTML elements.
+# FlagURL args.url
+# FlagSeparator args.separator
+# SeverityColors: severity.colors
+# SeverityHeaders: severity.headers
+# SeverityColumnHeaders: severity.column_headers
+# ProjectNames: project_names, or project_list[*][0]
+# WarnPatternsSeverity: warn_patterns[*]['severity']
+# WarnPatternsDescription: warn_patterns[*]['description']
+# WarnPatternsOption: warn_patterns[*]['option']
+# WarningMessages: warning_messages
+# Warnings: warning_records
+# StatsHeader: warning count table header row
+# StatsRows: array of warning count table rows
+#
+# New dynamic HTML page's dynamic JavaScript data:
+#
+# New dynamic HTML related function to emit data:
+# escape_string, strip_escape_string, emit_warning_arrays
+# emit_js_data():
+#
+# To emit csv files of warning message counts:
+# flag --gencsv
+# description_for_csv, string_for_csv:
+# count_severity(sev, kind):
+# dump_csv():
+
import argparse
import re
parser = argparse.ArgumentParser(description='Convert a build log into HTML')
parser.add_argument('--gencsv',
help='Generate a CSV file with number of various warnings',
- action="store_true",
+ action='store_true',
default=False)
parser.add_argument('--byproject',
help='Separate warnings in HTML output by project names',
- action="store_true",
+ action='store_true',
default=False)
parser.add_argument('--url',
help='Root URL of an Android source code tree prefixed '
@@ -23,33 +101,38 @@
help='Path to build.log file')
args = parser.parse_args()
-# if you add another level, don't forget to give it a color below
-class severity:
- UNKNOWN = 0
- FIXMENOW = 1
- HIGH = 2
- MEDIUM = 3
- LOW = 4
- TIDY = 5
- HARMLESS = 6
- SKIP = 7
- attributes = [
- ['lightblue', 'Unknown', 'Unknown warnings'],
- ['fuchsia', 'FixNow', 'Critical warnings, fix me now'],
- ['red', 'High', 'High severity warnings'],
- ['orange', 'Medium', 'Medium severity warnings'],
- ['yellow', 'Low', 'Low severity warnings'],
- ['peachpuff', 'Tidy', 'Clang-Tidy warnings'],
- ['limegreen', 'Harmless', 'Harmless warnings'],
- ['grey', 'Unhandled', 'Unhandled warnings']
- ]
- color = [a[0] for a in attributes]
- columnheader = [a[1] for a in attributes]
- header = [a[2] for a in attributes]
- # order to dump by severity
- kinds = [FIXMENOW, HIGH, MEDIUM, LOW, TIDY, HARMLESS, UNKNOWN, SKIP]
-warnpatterns = [
+class severity: # pylint:disable=invalid-name,old-style-class
+ """Severity levels and attributes."""
+ # numbered by dump order
+ FIXMENOW = 0
+ HIGH = 1
+ MEDIUM = 2
+ LOW = 3
+ TIDY = 4
+ HARMLESS = 5
+ UNKNOWN = 6
+ SKIP = 7
+ range = range(8)
+ attributes = [
+ # pylint:disable=bad-whitespace
+ ['fuchsia', 'FixNow', 'Critical warnings, fix me now'],
+ ['red', 'High', 'High severity warnings'],
+ ['orange', 'Medium', 'Medium severity warnings'],
+ ['yellow', 'Low', 'Low severity warnings'],
+ ['peachpuff', 'Tidy', 'Clang-Tidy warnings'],
+ ['limegreen', 'Harmless', 'Harmless warnings'],
+ ['lightblue', 'Unknown', 'Unknown warnings'],
+ ['grey', 'Unhandled', 'Unhandled warnings']
+ ]
+ colors = [a[0] for a in attributes]
+ column_headers = [a[1] for a in attributes]
+ headers = [a[2] for a in attributes]
+
+warn_patterns = [
+ # TODO(chh): fix pylint space and indentation warnings
+ # pylint:disable=bad-whitespace,bad-continuation,
+ # pylint:disable=line-too-long,g-inconsistent-quotes
{ 'category':'make', 'severity':severity.MEDIUM,
'description':'make: overriding commands/ignoring old commands',
'patterns':[r".*: warning: overriding commands for target .+",
@@ -71,7 +154,7 @@
'patterns':[r".*: warning: implicit declaration of function .+",
r".*: warning: implicitly declaring library function" ] },
{ 'category':'C/C++', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, conflicting types for ...',
'patterns':[r".*: warning: conflicting types for '.+'"] },
{ 'category':'C/C++', 'severity':severity.HIGH, 'option':'-Wtype-limits',
'description':'Expression always evaluates to true or false',
@@ -146,7 +229,7 @@
'description':'Need virtual destructor',
'patterns':[r".*: warning: delete called .* has virtual functions but non-virtual destructor"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, near initialization for ...',
'patterns':[r".*: warning: \(near initialization for '.+'\)"] },
{ 'category':'C/C++', 'severity':severity.MEDIUM, 'option':'-Wdate-time',
'description':'Expansion of data or time macro',
@@ -286,7 +369,7 @@
r".*: warning: Access to .+ results in a dereference of a null pointer",
r".*: warning: Null pointer argument in"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, parameter name (without types) in function declaration',
'patterns':[r".*: warning: parameter names \(without types\) in function declaration"] },
{ 'category':'C/C++', 'severity':severity.MEDIUM, 'option':'-Wstrict-aliasing',
'description':'Dereferencing <foo> breaks strict aliasing rules',
@@ -302,7 +385,7 @@
'description':'Symbol redefined',
'patterns':[r".*: warning: "".+"" redefined"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, ... location of the previous definition',
'patterns':[r".*: warning: this is the location of the previous definition"] },
{ 'category':'ld', 'severity':severity.MEDIUM,
'description':'ld: type and size of dynamic symbol are not defined',
@@ -338,7 +421,7 @@
'description':'Redundant declaration',
'patterns':[r".*: warning: redundant redeclaration of '.+'"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, previous declaration ... was here',
'patterns':[r".*: warning: previous declaration of '.+' was here"] },
{ 'category':'C/C++', 'severity':severity.MEDIUM, 'option':'-Wswitch-enum',
'description':'Enum value not handled in switch',
@@ -1141,13 +1224,13 @@
'patterns':[r".*: warning: '.+' will be initialized after",
r".*: warning: field .+ will be initialized after .+Wreorder"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, ....',
'patterns':[r".*: warning: '.+'"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, base ...',
'patterns':[r".*: warning: base '.+'"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, when initialized here',
'patterns':[r".*: warning: when initialized here"] },
{ 'category':'C/C++', 'severity':severity.MEDIUM, 'option':'-Wmissing-parameter-type',
'description':'Parameter type not specified',
@@ -1158,6 +1241,8 @@
{ 'category':'C/C++', 'severity':severity.MEDIUM, 'option':'-Wmissing-noreturn',
'description':'Missing noreturn',
'patterns':[r".*: warning: function '.*' could be declared with attribute 'noreturn'"] },
+ # pylint:disable=anomalous-backslash-in-string
+ # TODO(chh): fix the backslash pylint warning.
{ 'category':'gcc', 'severity':severity.MEDIUM,
'description':'Invalid option for C file',
'patterns':[r".*: warning: command line option "".+"" is valid for C\+\+\/ObjC\+\+ but not for C"] },
@@ -1191,7 +1276,7 @@
'description':'<foo> declared inside parameter list, scope limited to this definition',
'patterns':[r".*: warning: '.+' declared inside parameter list"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, its scope is only this ...',
'patterns':[r".*: warning: its scope is only this definition or declaration, which is probably not what you want"] },
{ 'category':'C/C++', 'severity':severity.LOW, 'option':'-Wcomment',
'description':'Line continuation inside comment',
@@ -1262,7 +1347,7 @@
'description':'Overload resolution chose to promote from unsigned or enum to signed type' ,
'patterns':[r".*: warning: passing '.+' chooses '.+' over '.+'.*Wsign-promo"] },
{ 'category':'cont.', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, in call to ...',
'patterns':[r".*: warning: in call to '.+'"] },
{ 'category':'C/C++', 'severity':severity.HIGH, 'option':'-Wextra',
'description':'Base should be explicitly initialized in copy constructor',
@@ -1454,13 +1539,13 @@
# these next ones are to deal with formatting problems resulting from the log being mixed up by 'make -j'
{ 'category':'C/C++', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, ,',
'patterns':[r".*: warning: ,$"] },
{ 'category':'C/C++', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip,',
'patterns':[r".*: warning: $"] },
{ 'category':'C/C++', 'severity':severity.SKIP,
- 'description':'',
+ 'description':'skip, In file included from ...',
'patterns':[r".*: warning: In file included from .+,"] },
# warnings from clang-tidy
@@ -1577,14 +1662,11 @@
'patterns':[r".*: warning: .+"] },
]
-for w in warnpatterns:
- w['members'] = []
- if 'option' not in w:
- w['option'] = ''
# A list of [project_name, file_path_pattern].
# project_name should not contain comma, to be used in CSV output.
-projectlist = [
+project_list = [
+ # pylint:disable=bad-whitespace,g-inconsistent-quotes,line-too-long
['art', r"(^|.*/)art/.*: warning:"],
['bionic', r"(^|.*/)bionic/.*: warning:"],
['bootable', r"(^|.*/)bootable/.*: warning:"],
@@ -1598,16 +1680,56 @@
# match external/google* before external/
['external/google', r"(^|.*/)external/google.*: warning:"],
['external/non-google', r"(^|.*/)external/.*: warning:"],
- ['frameworks', r"(^|.*/)frameworks/.*: warning:"],
- ['hardware', r"(^|.*/)hardware/.*: warning:"],
+ ['frameworks/av/camera',r"(^|.*/)frameworks/av/camera/.*: warning:"],
+ ['frameworks/av/cmds', r"(^|.*/)frameworks/av/cmds/.*: warning:"],
+ ['frameworks/av/drm', r"(^|.*/)frameworks/av/drm/.*: warning:"],
+ ['frameworks/av/include',r"(^|.*/)frameworks/av/include/.*: warning:"],
+ ['frameworks/av/media', r"(^|.*/)frameworks/av/media/.*: warning:"],
+ ['frameworks/av/radio', r"(^|.*/)frameworks/av/radio/.*: warning:"],
+ ['frameworks/av/services', r"(^|.*/)frameworks/av/services/.*: warning:"],
+ ['frameworks/av/Other', r"(^|.*/)frameworks/av/.*: warning:"],
+ ['frameworks/base', r"(^|.*/)frameworks/base/.*: warning:"],
+ ['frameworks/compile', r"(^|.*/)frameworks/compile/.*: warning:"],
+ ['frameworks/minikin', r"(^|.*/)frameworks/minikin/.*: warning:"],
+ ['frameworks/native', r"(^|.*/)frameworks/native/.*: warning:"],
+ ['frameworks/opt', r"(^|.*/)frameworks/opt/.*: warning:"],
+ ['frameworks/rs', r"(^|.*/)frameworks/rs/.*: warning:"],
+ ['frameworks/webview', r"(^|.*/)frameworks/webview/.*: warning:"],
+ ['frameworks/wilhelm', r"(^|.*/)frameworks/wilhelm/.*: warning:"],
+ ['frameworks/Other', r"(^|.*/)frameworks/.*: warning:"],
+ ['hardware/akm', r"(^|.*/)hardware/akm/.*: warning:"],
+ ['hardware/broadcom', r"(^|.*/)hardware/broadcom/.*: warning:"],
+ ['hardware/google', r"(^|.*/)hardware/google/.*: warning:"],
+ ['hardware/intel', r"(^|.*/)hardware/intel/.*: warning:"],
+ ['hardware/interfaces', r"(^|.*/)hardware/interfaces/.*: warning:"],
+ ['hardware/libhardware',r"(^|.*/)hardware/libhardware/.*: warning:"],
+ ['hardware/libhardware_legacy',r"(^|.*/)hardware/libhardware_legacy/.*: warning:"],
+ ['hardware/qcom', r"(^|.*/)hardware/qcom/.*: warning:"],
+ ['hardware/ril', r"(^|.*/)hardware/ril/.*: warning:"],
+ ['hardware/Other', r"(^|.*/)hardware/.*: warning:"],
['kernel', r"(^|.*/)kernel/.*: warning:"],
['libcore', r"(^|.*/)libcore/.*: warning:"],
- ['libnativehelper', r"(^|.*/)libnativehelper/.*: warning:"],
+ ['libnativehelper', r"(^|.*/)libnativehelper/.*: warning:"],
['ndk', r"(^|.*/)ndk/.*: warning:"],
+ # match vendor/unbungled_google/packages before other packages
+ ['unbundled_google', r"(^|.*/)unbundled_google/.*: warning:"],
['packages', r"(^|.*/)packages/.*: warning:"],
['pdk', r"(^|.*/)pdk/.*: warning:"],
['prebuilts', r"(^|.*/)prebuilts/.*: warning:"],
- ['system', r"(^|.*/)system/.*: warning:"],
+ ['system/bt', r"(^|.*/)system/bt/.*: warning:"],
+ ['system/connectivity', r"(^|.*/)system/connectivity/.*: warning:"],
+ ['system/core', r"(^|.*/)system/core/.*: warning:"],
+ ['system/extras', r"(^|.*/)system/extras/.*: warning:"],
+ ['system/gatekeeper', r"(^|.*/)system/gatekeeper/.*: warning:"],
+ ['system/keymaster', r"(^|.*/)system/keymaster/.*: warning:"],
+ ['system/libhwbinder', r"(^|.*/)system/libhwbinder/.*: warning:"],
+ ['system/media', r"(^|.*/)system/media/.*: warning:"],
+ ['system/netd', r"(^|.*/)system/netd/.*: warning:"],
+ ['system/security', r"(^|.*/)system/security/.*: warning:"],
+ ['system/sepolicy', r"(^|.*/)system/sepolicy/.*: warning:"],
+ ['system/tools', r"(^|.*/)system/tools/.*: warning:"],
+ ['system/vold', r"(^|.*/)system/vold/.*: warning:"],
+ ['system/Other', r"(^|.*/)system/.*: warning:"],
['toolchain', r"(^|.*/)toolchain/.*: warning:"],
['test', r"(^|.*/)test/.*: warning:"],
['tools', r"(^|.*/)tools/.*: warning:"],
@@ -1615,428 +1737,608 @@
['vendor/google', r"(^|.*/)vendor/google.*: warning:"],
['vendor/non-google', r"(^|.*/)vendor/.*: warning:"],
# keep out/obj and other patterns at the end.
- ['out/obj', r".*/(gen|obj[^/]*)/(include|EXECUTABLES|SHARED_LIBRARIES|STATIC_LIBRARIES)/.*: warning:"],
+ ['out/obj', r".*/(gen|obj[^/]*)/(include|EXECUTABLES|SHARED_LIBRARIES|STATIC_LIBRARIES|NATIVE_TESTS)/.*: warning:"],
['other', r".*: warning:"],
]
-projectpatterns = []
-for p in projectlist:
- projectpatterns.append({'description':p[0], 'members':[], 'pattern':re.compile(p[1])})
+project_patterns = []
+project_names = []
+warning_messages = []
+warning_records = []
-projectnames = [p[0] for p in projectlist]
-# Each warning pattern has 3 dictionaries:
-# (1) 'projects' maps a project name to number of warnings in that project.
-# (2) 'projectanchor' maps a project name to its anchor number for HTML.
-# (3) 'projectwarning' maps a project name to a list of warning of that project.
-for w in warnpatterns:
+def initialize_arrays():
+ """Complete global arrays before they are used."""
+ global project_names, project_patterns
+ project_names = [p[0] for p in project_list]
+ project_patterns = [re.compile(p[1]) for p in project_list]
+ for w in warn_patterns:
+ w['members'] = []
+ if 'option' not in w:
+ w['option'] = ''
+ # Each warning pattern has a 'projects' dictionary, that
+ # maps a project name to number of warnings in that project.
w['projects'] = {}
- w['projectanchor'] = {}
- w['projectwarning'] = {}
-platformversion = 'unknown'
-targetproduct = 'unknown'
-targetvariant = 'unknown'
+
+initialize_arrays()
+
+
+platform_version = 'unknown'
+target_product = 'unknown'
+target_variant = 'unknown'
##### Data and functions to dump html file. ##################################
-anchor = 0
-cur_row_class = 0
-
-html_script_style = """\
- <script type="text/javascript">
- function expand(id) {
- var e = document.getElementById(id);
+html_head_scripts = """\
+ <script type="text/javascript">
+ function expand(id) {
+ var e = document.getElementById(id);
+ var f = document.getElementById(id + "_mark");
+ if (e.style.display == 'block') {
+ e.style.display = 'none';
+ f.innerHTML = '⊕';
+ }
+ else {
+ e.style.display = 'block';
+ f.innerHTML = '⊖';
+ }
+ };
+ function expandCollapse(show) {
+ for (var id = 1; ; id++) {
+ var e = document.getElementById(id + "");
var f = document.getElementById(id + "_mark");
- if (e.style.display == 'block') {
- e.style.display = 'none';
- f.innerHTML = '⊕';
- }
- else {
- e.style.display = 'block';
- f.innerHTML = '⊖';
- }
- };
- function expand_collapse(show) {
- for (var id = 1; ; id++) {
- var e = document.getElementById(id + "");
- var f = document.getElementById(id + "_mark");
- if (!e || !f) break;
- e.style.display = (show ? 'block' : 'none');
- f.innerHTML = (show ? '⊖' : '⊕');
- }
- };
- </script>
- <style type="text/css">
- th,td{border-collapse:collapse; border:1px solid black;}
- .button{color:blue;font-size:110%;font-weight:bolder;}
- .bt{color:black;background-color:transparent;border:none;outline:none;
- font-size:140%;font-weight:bolder;}
- .c0{background-color:#e0e0e0;}
- .c1{background-color:#d0d0d0;}
- .t1{border-collapse:collapse; width:100%; border:1px solid black;}
- </style>\n"""
+ if (!e || !f) break;
+ e.style.display = (show ? 'block' : 'none');
+ f.innerHTML = (show ? '⊖' : '⊕');
+ }
+ };
+ </script>
+ <style type="text/css">
+ th,td{border-collapse:collapse; border:1px solid black;}
+ .button{color:blue;font-size:110%;font-weight:bolder;}
+ .bt{color:black;background-color:transparent;border:none;outline:none;
+ font-size:140%;font-weight:bolder;}
+ .c0{background-color:#e0e0e0;}
+ .c1{background-color:#d0d0d0;}
+ .t1{border-collapse:collapse; width:100%; border:1px solid black;}
+ </style>
+ <script src="https://www.gstatic.com/charts/loader.js"></script>
+"""
-def output(text):
- print text,
+def html_big(param):
+ return '<font size="+2">' + param + '</font>'
-def htmlbig(param):
- return '<font size="+2">' + param + '</font>'
-def dumphtmlprologue(title):
- output('<html>\n<head>\n')
- output('<title>' + title + '</title>\n')
- output(html_script_style)
- output('</head>\n<body>\n')
- output(htmlbig(title))
- output('<p>\n')
+def dump_html_prologue(title):
+ print '<html>\n<head>'
+ print '<title>' + title + '</title>'
+ print html_head_scripts
+ emit_stats_by_project()
+ print '</head>\n<body>'
+ print html_big(title)
+ print '<p>'
-def dumphtmlepilogue():
- output('</body>\n</head>\n</html>\n')
-def tablerow(text):
- global cur_row_class
+def dump_html_epilogue():
+ print '</body>\n</head>\n</html>'
+
+
+def sort_warnings():
+ for i in warn_patterns:
+ i['members'] = sorted(set(i['members']))
+
+
+def emit_stats_by_project():
+ """Dump a google chart table of warnings per project and severity."""
+ # warnings[p][s] is number of warnings in project p of severity s.
+ warnings = {p: {s: 0 for s in severity.range} for p in project_names}
+ for i in warn_patterns:
+ s = i['severity']
+ for p in i['projects']:
+ warnings[p][s] += i['projects'][p]
+
+ # total_by_project[p] is number of warnings in project p.
+ total_by_project = {p: sum(warnings[p][s] for s in severity.range)
+ for p in project_names}
+
+ # total_by_severity[s] is number of warnings of severity s.
+ total_by_severity = {s: sum(warnings[p][s] for p in project_names)
+ for s in severity.range}
+
+ # emit table header
+ stats_header = ['Project']
+ for s in severity.range:
+ if total_by_severity[s]:
+ stats_header.append("<span style='background-color:{}'>{}</span>".
+ format(severity.colors[s],
+ severity.column_headers[s]))
+ stats_header.append('TOTAL')
+
+ # emit a row of warning counts per project, skip no-warning projects
+ total_all_projects = 0
+ stats_rows = []
+ for p in project_names:
+ if total_by_project[p]:
+ one_row = [p]
+ for s in severity.range:
+ if total_by_severity[s]:
+ one_row.append(warnings[p][s])
+ one_row.append(total_by_project[p])
+ stats_rows.append(one_row)
+ total_all_projects += total_by_project[p]
+
+ # emit a row of warning counts per severity
+ total_all_severities = 0
+ one_row = ['<b>TOTAL</b>']
+ for s in severity.range:
+ if total_by_severity[s]:
+ one_row.append(total_by_severity[s])
+ total_all_severities += total_by_severity[s]
+ one_row.append(total_all_projects)
+ stats_rows.append(one_row)
+ print '<script>'
+ emit_const_string_array('StatsHeader', stats_header)
+ emit_const_object_array('StatsRows', stats_rows)
+ print draw_table_javascript
+ print '</script>'
+
+
+def dump_stats():
+ """Dump some stats about total number of warnings and such."""
+ known = 0
+ skipped = 0
+ unknown = 0
+ sort_warnings()
+ for i in warn_patterns:
+ if i['severity'] == severity.UNKNOWN:
+ unknown += len(i['members'])
+ elif i['severity'] == severity.SKIP:
+ skipped += len(i['members'])
+ else:
+ known += len(i['members'])
+ print 'Number of classified warnings: <b>' + str(known) + '</b><br>'
+ print 'Number of skipped warnings: <b>' + str(skipped) + '</b><br>'
+ print 'Number of unclassified warnings: <b>' + str(unknown) + '</b><br>'
+ total = unknown + known + skipped
+ extra_msg = ''
+ if total < 1000:
+ extra_msg = ' (low count may indicate incremental build)'
+ print 'Total number of warnings: <b>' + str(total) + '</b>' + extra_msg
+
+
+# New base table of warnings, [severity, warn_id, project, warning_message]
+# Need buttons to show warnings in different grouping options.
+# (1) Current, group by severity, id for each warning pattern
+# sort by severity, warn_id, warning_message
+# (2) Current --byproject, group by severity,
+# id for each warning pattern + project name
+# sort by severity, warn_id, project, warning_message
+# (3) New, group by project + severity,
+# id for each warning pattern
+# sort by project, severity, warn_id, warning_message
+def emit_buttons():
+ print ('<button class="button" onclick="expandCollapse(1);">'
+ 'Expand all warnings</button>\n'
+ '<button class="button" onclick="expandCollapse(0);">'
+ 'Collapse all warnings</button>\n'
+ '<button class="button" onclick="groupBySeverity();">'
+ 'Group warnings by severity</button>\n'
+ '<button class="button" onclick="groupByProject();">'
+ 'Group warnings by project</button><br>')
+
+
+def all_patterns(category):
+ patterns = ''
+ for i in category['patterns']:
+ patterns += i
+ patterns += ' / '
+ return patterns
+
+
+def dump_fixed():
+ """Show which warnings no longer occur."""
+ anchor = 'fixed_warnings'
+ mark = anchor + '_mark'
+ print ('\n<br><p style="background-color:lightblue"><b>'
+ '<button id="' + mark + '" '
+ 'class="bt" onclick="expand(\'' + anchor + '\');">'
+ '⊕</button> Fixed warnings. '
+ 'No more occurrences. Please consider turning these into '
+ 'errors if possible, before they are reintroduced in to the build'
+ ':</b></p>')
+ print '<blockquote>'
+ fixed_patterns = []
+ for i in warn_patterns:
+ if not i['members']:
+ fixed_patterns.append(i['description'] + ' (' +
+ all_patterns(i) + ')')
+ if i['option']:
+ fixed_patterns.append(' ' + i['option'])
+ fixed_patterns.sort()
+ print '<div id="' + anchor + '" style="display:none;"><table>'
+ cur_row_class = 0
+ for text in fixed_patterns:
cur_row_class = 1 - cur_row_class
# remove last '\n'
t = text[:-1] if text[-1] == '\n' else text
- output('<tr><td class="c' + str(cur_row_class) + '">' + t + '</td></tr>\n')
+ print '<tr><td class="c' + str(cur_row_class) + '">' + t + '</td></tr>'
+ print '</table></div>'
+ print '</blockquote>'
-def sortwarnings():
- for i in warnpatterns:
- i['members'] = sorted(set(i['members']))
-# dump a table of warnings per project and severity
-def dumpstatsbyproject():
- projects = set(projectnames)
- severities = set(severity.kinds)
+def find_project_index(line):
+ for p in range(len(project_patterns)):
+ if project_patterns[p].match(line):
+ return p
+ return -1
- # warnings[p][s] is number of warnings in project p of severity s.
- warnings = {p:{s:0 for s in severity.kinds} for p in projectnames}
- for i in warnpatterns:
- s = i['severity']
- for p in i['projects']:
- warnings[p][s] += i['projects'][p]
- # totalbyproject[p] is number of warnings in project p.
- totalbyproject = {p:sum(warnings[p][s] for s in severity.kinds)
- for p in projectnames}
-
- # totalbyseverity[s] is number of warnings of severity s.
- totalbyseverity = {s:sum(warnings[p][s] for p in projectnames)
- for s in severity.kinds}
-
- # emit table header
- output('<blockquote><table border=1>\n<tr><th>Project</th>\n')
- for s in severity.kinds:
- if totalbyseverity[s]:
- output('<th width="8%"><span style="background-color:{}">{}</span></th>'.
- format(severity.color[s], severity.columnheader[s]))
- output('<th>TOTAL</th></tr>\n')
-
- # emit a row of warning counts per project, skip no-warning projects
- totalallprojects = 0
- for p in projectnames:
- if totalbyproject[p]:
- output('<tr><td align="left">{}</td>'.format(p))
- for s in severity.kinds:
- if totalbyseverity[s]:
- output('<td align="right">{}</td>'.format(warnings[p][s]))
- output('<td align="right">{}</td>'.format(totalbyproject[p]))
- totalallprojects += totalbyproject[p]
- output('</tr>\n')
-
- # emit a row of warning counts per severity
- totalallseverities = 0
- output('<tr><td align="right">TOTAL</td>')
- for s in severity.kinds:
- if totalbyseverity[s]:
- output('<td align="right">{}</td>'.format(totalbyseverity[s]))
- totalallseverities += totalbyseverity[s]
- output('<td align="right">{}</td></tr>\n'.format(totalallprojects))
-
- # at the end of table, verify total counts
- output('</table></blockquote><br>\n')
- if totalallprojects != totalallseverities:
- output('<h3>ERROR: Sum of warnings by project ' +
- '!= Sum of warnings by severity.</h3>\n')
-
-# dump some stats about total number of warnings and such
-def dumpstats():
- known = 0
- skipped = 0
- unknown = 0
- sortwarnings()
- for i in warnpatterns:
- if i['severity'] == severity.UNKNOWN:
- unknown += len(i['members'])
- elif i['severity'] == severity.SKIP:
- skipped += len(i['members'])
+def classify_warning(line):
+ for i in range(len(warn_patterns)):
+ w = warn_patterns[i]
+ for cpat in w['compiled_patterns']:
+ if cpat.match(line):
+ w['members'].append(line)
+ p = find_project_index(line)
+ index = len(warning_messages)
+ warning_messages.append(line)
+ warning_records.append([i, p, index])
+ pname = '???' if p < 0 else project_names[p]
+ # Count warnings by project.
+ if pname in w['projects']:
+ w['projects'][pname] += 1
else:
- known += len(i['members'])
- output('\nNumber of classified warnings: <b>' + str(known) + '</b><br>' )
- output('\nNumber of skipped warnings: <b>' + str(skipped) + '</b><br>')
- output('\nNumber of unclassified warnings: <b>' + str(unknown) + '</b><br>')
- total = unknown + known + skipped
- output('\nTotal number of warnings: <b>' + str(total) + '</b>')
- if total < 1000:
- output('(low count may indicate incremental build)')
- output('<br><br>\n')
-
-def emitbuttons():
- output('<button class="button" onclick="expand_collapse(1);">' +
- 'Expand all warnings</button>\n' +
- '<button class="button" onclick="expand_collapse(0);">' +
- 'Collapse all warnings</button><br>\n')
-
-# dump everything for a given severity
-def dumpseverity(sev):
- global anchor
- total = 0
- for i in warnpatterns:
- if i['severity'] == sev:
- total = total + len(i['members'])
- output('\n<br><span style="background-color:' + severity.color[sev] + '"><b>' +
- severity.header[sev] + ': ' + str(total) + '</b></span>\n')
- output('<blockquote>\n')
- for i in warnpatterns:
- if i['severity'] == sev and len(i['members']) > 0:
- anchor += 1
- i['anchor'] = str(anchor)
- if args.byproject:
- dumpcategorybyproject(sev, i)
- else:
- dumpcategory(sev, i)
- output('</blockquote>\n')
-
-# emit all skipped project anchors for expand_collapse.
-def dumpskippedanchors():
- output('<div style="display:none;">\n') # hide these fake elements
- for i in warnpatterns:
- if i['severity'] == severity.SKIP and len(i['members']) > 0:
- projects = i['projectwarning'].keys()
- for p in projects:
- output('<div id="' + i['projectanchor'][p] + '"></div>' +
- '<div id="' + i['projectanchor'][p] + '_mark"></div>\n')
- output('</div>\n')
-
-def allpatterns(cat):
- pats = ''
- for i in cat['patterns']:
- pats += i
- pats += ' / '
- return pats
-
-def descriptionfor(cat):
- if cat['description'] != '':
- return cat['description']
- return allpatterns(cat)
+ w['projects'][pname] = 1
+ return
+ else:
+ # If we end up here, there was a problem parsing the log
+ # probably caused by 'make -j' mixing the output from
+ # 2 or more concurrent compiles
+ pass
-# show which warnings no longer occur
-def dumpfixed():
- global anchor
- anchor += 1
- mark = str(anchor) + '_mark'
- output('\n<br><p style="background-color:lightblue"><b>' +
- '<button id="' + mark + '" ' +
- 'class="bt" onclick="expand(' + str(anchor) + ');">' +
- '⊕</button> Fixed warnings. ' +
- 'No more occurences. Please consider turning these into ' +
- 'errors if possible, before they are reintroduced in to the build' +
- ':</b></p>\n')
- output('<blockquote>\n')
- fixed_patterns = []
- for i in warnpatterns:
- if len(i['members']) == 0:
- fixed_patterns.append(i['description'] + ' (' +
- allpatterns(i) + ')')
- if i['option']:
- fixed_patterns.append(' ' + i['option'])
- fixed_patterns.sort()
- output('<div id="' + str(anchor) + '" style="display:none;"><table>\n')
- for i in fixed_patterns:
- tablerow(i)
- output('</table></div>\n')
- output('</blockquote>\n')
+def compile_patterns():
+ """Precompiling every pattern speeds up parsing by about 30x."""
+ for i in warn_patterns:
+ i['compiled_patterns'] = []
+ for pat in i['patterns']:
+ i['compiled_patterns'].append(re.compile(pat))
-def warningwithurl(line):
- if not args.url:
- return line
- m = re.search( r'^([^ :]+):(\d+):(.+)', line, re.M|re.I)
- if not m:
- return line
- filepath = m.group(1)
- linenumber = m.group(2)
- warning = m.group(3)
- if args.separator:
- return '<a href="' + args.url + '/' + filepath + args.separator + linenumber + '">' + filepath + ':' + linenumber + '</a>:' + warning
+
+def parse_input_file():
+ """Parse input file, match warning lines."""
+ global platform_version
+ global target_product
+ global target_variant
+ infile = open(args.buildlog, 'r')
+ line_counter = 0
+
+ warning_pattern = re.compile('.* warning:.*')
+ compile_patterns()
+
+ # read the log file and classify all the warnings
+ warning_lines = set()
+ for line in infile:
+ # replace fancy quotes with plain ol' quotes
+ line = line.replace('‘', "'")
+ line = line.replace('’', "'")
+ if warning_pattern.match(line):
+ if line not in warning_lines:
+ classify_warning(line)
+ warning_lines.add(line)
+ elif line_counter < 50:
+ # save a little bit of time by only doing this for the first few lines
+ line_counter += 1
+ m = re.search('(?<=^PLATFORM_VERSION=).*', line)
+ if m is not None:
+ platform_version = m.group(0)
+ m = re.search('(?<=^TARGET_PRODUCT=).*', line)
+ if m is not None:
+ target_product = m.group(0)
+ m = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line)
+ if m is not None:
+ target_variant = m.group(0)
+
+
+# Return s with escaped quotation characters.
+def escape_string(s):
+ return s.replace('"', '\\"')
+
+
+# Return s without trailing '\n' and escape the quotation characters.
+def strip_escape_string(s):
+ if not s:
+ return s
+ s = s[:-1] if s[-1] == '\n' else s
+ return escape_string(s)
+
+
+def emit_warning_array(name):
+ print 'var warning_{} = ['.format(name)
+ for i in range(len(warn_patterns)):
+ print '{},'.format(warn_patterns[i][name])
+ print '];'
+
+
+def emit_warning_arrays():
+ emit_warning_array('severity')
+ print 'var warning_description = ['
+ for i in range(len(warn_patterns)):
+ if warn_patterns[i]['members']:
+ print '"{}",'.format(escape_string(warn_patterns[i]['description']))
else:
- return '<a href="' + args.url + '/' + filepath + '">' + filepath + '</a>:' + linenumber + ':' + warning
+ print '"",' # no such warning
+ print '];'
-def dumpgroup(sev, anchor, description, warnings):
- mark = anchor + '_mark'
- output('\n<table class="t1">\n')
- output('<tr bgcolor="' + severity.color[sev] + '">' +
- '<td><button class="bt" id="' + mark +
- '" onclick="expand(\'' + anchor + '\');">' +
- '⊕</button> ' + description + '</td></tr>\n')
- output('</table>\n')
- output('<div id="' + anchor + '" style="display:none;">')
- output('<table class="t1">\n')
- for i in warnings:
- tablerow(warningwithurl(i))
- output('</table></div>\n')
+scripts_for_warning_groups = """
+ function compareMessages(x1, x2) { // of the same warning type
+ return (WarningMessages[x1[2]] <= WarningMessages[x2[2]]) ? -1 : 1;
+ }
+ function byMessageCount(x1, x2) {
+ return x2[2] - x1[2]; // reversed order
+ }
+ function bySeverityMessageCount(x1, x2) {
+ // orer by severity first
+ if (x1[1] != x2[1])
+ return x1[1] - x2[1];
+ return byMessageCount(x1, x2);
+ }
+ const ParseLinePattern = /^([^ :]+):(\\d+):(.+)/;
+ function addURL(line) {
+ if (FlagURL == "") return line;
+ if (FlagSeparator == "") {
+ return line.replace(ParseLinePattern,
+ "<a href='" + FlagURL + "/$1'>$1</a>:$2:$3");
+ }
+ return line.replace(ParseLinePattern,
+ "<a href='" + FlagURL + "/$1" + FlagSeparator + "$2'>$1:$2</a>:$3");
+ }
+ function createArrayOfDictionaries(n) {
+ var result = [];
+ for (var i=0; i<n; i++) result.push({});
+ return result;
+ }
+ function groupWarningsBySeverity() {
+ // groups is an array of dictionaries,
+ // each dictionary maps from warning type to array of warning messages.
+ var groups = createArrayOfDictionaries(SeverityColors.length);
+ for (var i=0; i<Warnings.length; i++) {
+ var w = Warnings[i][0];
+ var s = WarnPatternsSeverity[w];
+ var k = w.toString();
+ if (!(k in groups[s]))
+ groups[s][k] = [];
+ groups[s][k].push(Warnings[i]);
+ }
+ return groups;
+ }
+ function groupWarningsByProject() {
+ var groups = createArrayOfDictionaries(ProjectNames.length);
+ for (var i=0; i<Warnings.length; i++) {
+ var w = Warnings[i][0];
+ var p = Warnings[i][1];
+ var k = w.toString();
+ if (!(k in groups[p]))
+ groups[p][k] = [];
+ groups[p][k].push(Warnings[i]);
+ }
+ return groups;
+ }
+ var GlobalAnchor = 0;
+ function createWarningSection(header, color, group) {
+ var result = "";
+ var groupKeys = [];
+ var totalMessages = 0;
+ for (var k in group) {
+ totalMessages += group[k].length;
+ groupKeys.push([k, WarnPatternsSeverity[parseInt(k)], group[k].length]);
+ }
+ groupKeys.sort(bySeverityMessageCount);
+ for (var idx=0; idx<groupKeys.length; idx++) {
+ var k = groupKeys[idx][0];
+ var messages = group[k];
+ var w = parseInt(k);
+ var wcolor = SeverityColors[WarnPatternsSeverity[w]];
+ var description = WarnPatternsDescription[w];
+ if (description.length == 0)
+ description = "???";
+ GlobalAnchor += 1;
+ result += "<table class='t1'><tr bgcolor='" + wcolor + "'><td>" +
+ "<button class='bt' id='" + GlobalAnchor + "_mark" +
+ "' onclick='expand(\\"" + GlobalAnchor + "\\");'>" +
+ "⊕</button> " +
+ description + " (" + messages.length + ")</td></tr></table>";
+ result += "<div id='" + GlobalAnchor +
+ "' style='display:none;'><table class='t1'>";
+ var c = 0;
+ messages.sort(compareMessages);
+ for (var i=0; i<messages.length; i++) {
+ result += "<tr><td class='c" + c + "'>" +
+ addURL(WarningMessages[messages[i][2]]) + "</td></tr>";
+ c = 1 - c;
+ }
+ result += "</table></div>";
+ }
+ if (result.length > 0) {
+ return "<br><span style='background-color:" + color + "'><b>" +
+ header + ": " + totalMessages +
+ "</b></span><blockquote><table class='t1'>" +
+ result + "</table></blockquote>";
-# dump warnings in a category
-def dumpcategory(sev, cat):
- description = descriptionfor(cat) + ' (' + str(len(cat['members'])) + ')'
- dumpgroup(sev, cat['anchor'], description, cat['members'])
-
-# similar to dumpcategory but output one table per project.
-def dumpcategorybyproject(sev, cat):
- warning = descriptionfor(cat)
- projects = cat['projectwarning'].keys()
- projects.sort()
- for p in projects:
- anchor = cat['projectanchor'][p]
- projectwarnings = cat['projectwarning'][p]
- description = '{}, in {} ({})'.format(warning, p, len(projectwarnings))
- dumpgroup(sev, anchor, description, projectwarnings)
-
-def findproject(line):
- for p in projectpatterns:
- if p['pattern'].match(line):
- return p['description']
- return '???'
-
-def classifywarning(line):
- global anchor
- for i in warnpatterns:
- for cpat in i['compiledpatterns']:
- if cpat.match(line):
- i['members'].append(line)
- pname = findproject(line)
- # Count warnings by project.
- if pname in i['projects']:
- i['projects'][pname] += 1
- else:
- i['projects'][pname] = 1
- # Collect warnings by project.
- if args.byproject:
- if pname in i['projectwarning']:
- i['projectwarning'][pname].append(line)
- else:
- i['projectwarning'][pname] = [line]
- if pname not in i['projectanchor']:
- anchor += 1
- i['projectanchor'][pname] = str(anchor)
- return
- else:
- # If we end up here, there was a problem parsing the log
- # probably caused by 'make -j' mixing the output from
- # 2 or more concurrent compiles
- pass
-
-# precompiling every pattern speeds up parsing by about 30x
-def compilepatterns():
- for i in warnpatterns:
- i['compiledpatterns'] = []
- for pat in i['patterns']:
- i['compiledpatterns'].append(re.compile(pat))
-
-def parseinputfile():
- global platformversion
- global targetproduct
- global targetvariant
- infile = open(args.buildlog, 'r')
- linecounter = 0
-
- warningpattern = re.compile('.* warning:.*')
- compilepatterns()
-
- # read the log file and classify all the warnings
- warninglines = set()
- for line in infile:
- # replace fancy quotes with plain ol' quotes
- line = line.replace("‘", "'");
- line = line.replace("’", "'");
- if warningpattern.match(line):
- if line not in warninglines:
- classifywarning(line)
- warninglines.add(line)
- else:
- # save a little bit of time by only doing this for the first few lines
- if linecounter < 50:
- linecounter +=1
- m = re.search('(?<=^PLATFORM_VERSION=).*', line)
- if m != None:
- platformversion = m.group(0)
- m = re.search('(?<=^TARGET_PRODUCT=).*', line)
- if m != None:
- targetproduct = m.group(0)
- m = re.search('(?<=^TARGET_BUILD_VARIANT=).*', line)
- if m != None:
- targetvariant = m.group(0)
+ }
+ return ""; // empty section
+ }
+ function generateSectionsBySeverity() {
+ var result = "";
+ var groups = groupWarningsBySeverity();
+ for (s=0; s<SeverityColors.length; s++) {
+ result += createWarningSection(SeverityHeaders[s], SeverityColors[s], groups[s]);
+ }
+ return result;
+ }
+ function generateSectionsByProject() {
+ var result = "";
+ var groups = groupWarningsByProject();
+ for (i=0; i<groups.length; i++) {
+ result += createWarningSection(ProjectNames[i], 'lightgrey', groups[i]);
+ }
+ return result;
+ }
+ function groupWarnings(generator) {
+ GlobalAnchor = 0;
+ var e = document.getElementById("warning_groups");
+ e.innerHTML = generator();
+ }
+ function groupBySeverity() {
+ groupWarnings(generateSectionsBySeverity);
+ }
+ function groupByProject() {
+ groupWarnings(generateSectionsByProject);
+ }
+"""
-# dump the html output to stdout
-def dumphtml():
- dumphtmlprologue('Warnings for ' + platformversion + ' - ' + targetproduct + ' - ' + targetvariant)
- dumpstats()
- dumpstatsbyproject()
- emitbuttons()
- # sort table based on number of members once dumpstats has deduplicated the
- # members.
- warnpatterns.sort(reverse=True, key=lambda i: len(i['members']))
- # Dump warnings by severity. If severity.SKIP warnings are not dumpped,
- # the project anchors should be dumped through dumpskippedanchors.
- for s in severity.kinds:
- dumpseverity(s)
- dumpfixed()
- dumphtmlepilogue()
+# Emit a JavaScript const string
+def emit_const_string(name, value):
+ print 'const ' + name + ' = "' + escape_string(value) + '";'
+
+
+# Emit a JavaScript const integer array.
+def emit_const_int_array(name, array):
+ print 'const ' + name + ' = ['
+ for n in array:
+ print str(n) + ','
+ print '];'
+
+
+# Emit a JavaScript const string array.
+def emit_const_string_array(name, array):
+ print 'const ' + name + ' = ['
+ for s in array:
+ print '"' + strip_escape_string(s) + '",'
+ print '];'
+
+
+# Emit a JavaScript const object array.
+def emit_const_object_array(name, array):
+ print 'const ' + name + ' = ['
+ for x in array:
+ print str(x) + ','
+ print '];'
+
+
+def emit_js_data():
+ """Dump dynamic HTML page's static JavaScript data."""
+ emit_const_string('FlagURL', args.url if args.url else '')
+ emit_const_string('FlagSeparator', args.separator if args.separator else '')
+ emit_const_string_array('SeverityColors', severity.colors)
+ emit_const_string_array('SeverityHeaders', severity.headers)
+ emit_const_string_array('SeverityColumnHeaders', severity.column_headers)
+ emit_const_string_array('ProjectNames', project_names)
+ emit_const_int_array('WarnPatternsSeverity',
+ [w['severity'] for w in warn_patterns])
+ emit_const_string_array('WarnPatternsDescription',
+ [w['description'] for w in warn_patterns])
+ emit_const_string_array('WarnPatternsOption',
+ [w['option'] for w in warn_patterns])
+ emit_const_string_array('WarningMessages', warning_messages)
+ emit_const_object_array('Warnings', warning_records)
+
+draw_table_javascript = """
+google.charts.load('current', {'packages':['table']});
+google.charts.setOnLoadCallback(drawTable);
+function drawTable() {
+ var data = new google.visualization.DataTable();
+ data.addColumn('string', StatsHeader[0]);
+ for (var i=1; i<StatsHeader.length; i++) {
+ data.addColumn('number', StatsHeader[i]);
+ }
+ data.addRows(StatsRows);
+ for (var i=0; i<StatsRows.length; i++) {
+ for (var j=0; j<StatsHeader.length; j++) {
+ data.setProperty(i, j, 'style', 'border:1px solid black;');
+ }
+ }
+ var table = new google.visualization.Table(document.getElementById('stats_table'));
+ table.draw(data, {allowHtml: true, alternatingRowStyle: true});
+}
+"""
+
+
+def dump_html():
+ """Dump the html output to stdout."""
+ dump_html_prologue('Warnings for ' + platform_version + ' - ' +
+ target_product + ' - ' + target_variant)
+ dump_stats()
+ print '<br><div id="stats_table"></div><br>'
+ print '\n<script>'
+ emit_js_data()
+ print scripts_for_warning_groups
+ print '</script>'
+ emit_buttons()
+ # Warning messages are grouped by severities or project names.
+ print '<br><div id="warning_groups"></div>'
+ if args.byproject:
+ print '<script>groupByProject();</script>'
+ else:
+ print '<script>groupBySeverity();</script>'
+ dump_fixed()
+ dump_html_epilogue()
##### Functions to count warnings and dump csv file. #########################
-def descriptionforcsv(cat):
- if cat['description'] == '':
- return '?'
- return cat['description']
-def stringforcsv(s):
- if ',' in s:
- return '"{}"'.format(s)
- return s
+def description_for_csv(category):
+ if not category['description']:
+ return '?'
+ return category['description']
-def countseverity(sev, kind):
- sum = 0
- for i in warnpatterns:
- if i['severity'] == sev and len(i['members']) > 0:
- n = len(i['members'])
- sum += n
- warning = stringforcsv(kind + ': ' + descriptionforcsv(i))
- print '{},,{}'.format(n, warning)
- # print number of warnings for each project, ordered by project name.
- projects = i['projects'].keys()
- projects.sort()
- for p in projects:
- print '{},{},{}'.format(i['projects'][p], p, warning)
- print '{},,{}'.format(sum, kind + ' warnings')
- return sum
+
+def string_for_csv(s):
+ # Only some Java warning desciptions have used quotation marks.
+ # TODO(chh): if s has double quote character, s should be quoted.
+ if ',' in s:
+ # TODO(chh): replace a double quote with two double quotes in s.
+ return '"{}"'.format(s)
+ return s
+
+
+def count_severity(sev, kind):
+ """Count warnings of given severity."""
+ total = 0
+ for i in warn_patterns:
+ if i['severity'] == sev and i['members']:
+ n = len(i['members'])
+ total += n
+ warning = string_for_csv(kind + ': ' + description_for_csv(i))
+ print '{},,{}'.format(n, warning)
+ # print number of warnings for each project, ordered by project name.
+ projects = i['projects'].keys()
+ projects.sort()
+ for p in projects:
+ print '{},{},{}'.format(i['projects'][p], p, warning)
+ print '{},,{}'.format(total, kind + ' warnings')
+ return total
+
# dump number of warnings in csv format to stdout
-def dumpcsv():
- sortwarnings()
- total = 0
- for s in severity.kinds:
- total += countseverity(s, severity.columnheader[s])
- print '{},,{}'.format(total, 'All warnings')
+def dump_csv():
+ """Dump number of warnings in csv format to stdout."""
+ sort_warnings()
+ total = 0
+ for s in severity.range:
+ total += count_severity(s, severity.column_headers[s])
+ print '{},,{}'.format(total, 'All warnings')
-parseinputfile()
+##### Main function starts here. #########################
+
+parse_input_file()
if args.gencsv:
- dumpcsv()
+ dump_csv()
else:
- dumphtml()
+ dump_html()