| OLD | NEW |
| (Empty) | |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 """ |
| 5 This script takes two warning summary files and reports on the new warnings |
| 6 and the fixed warnings. The warning summaries are created by |
| 7 warnings_by_type.py. |
| 8 |
| 9 A warning is identified by the source file and the warning text, without the |
| 10 Lines component or any line 'xxx' references within the warning. |
| 11 All warnings with the same signature are grouped together (duplicates are |
| 12 assumed to have been removed already). |
| 13 |
| 14 If a file contains multiple warnings with the same signature then a report |
| 15 will be generated for each warning when the warning count changes. |
| 16 """ |
| 17 |
| 18 import sys |
| 19 import re |
| 20 |
| 21 # Some sample warnings: |
| 22 # sctp_bsd_addr.c(182) : warning C28125: The function |
| 23 # 'InitializeCriticalSection' must be called from within a try/except block: |
| 24 # The requirement might be conditional. |
| 25 # exception_handler.cc(813) : warning C6387: 'child_thread_handle' could be '0': |
| 26 # this does not adhere to the specification for the function 'CloseHandle'. : |
| 27 # Lines: 773, 774, 775, 776, 777, 784, 802, 804, 809, 813 |
| 28 # unistr.cpp(1823) : warning C28193: 'temporary value' holds a value that must |
| 29 # be examined.: Lines: 1823, 1824 |
| 30 # Note "line '1428'" in this warning, and 'count went from 3 to 2': |
| 31 # scheduler.cc(1452) : warning C6246: Local declaration of 'node' hides |
| 32 # declaration of the same name in outer scope. For additional information, see |
| 33 # previous declaration at line '1428' of 'scheduler.cc'.: count went from 3 to 2 |
| 34 # Note "line 454" in this warning: |
| 35 # gurl.cc(449) : warning C28112: A variable (empty_gurl) which is accessed via |
| 36 # an Interlocked function must always be accessed via an Interlocked function. |
| 37 # See line 454: It is not always safe to access a variable which is accessed |
| 38 # via the Interlocked* family of functions in any other way. |
| 39 |
| 40 |
| 41 warningsToIgnore = [ |
| 42 # We assume that memory allocations never fail |
| 43 "C6255", # _alloca indicates failure by raising a stack overflow exception. |
| 44 "C6308", # 'realloc' might return null pointer, leaking memory |
| 45 "C6387", # Param could be '0': this does not adhere to the specification for |
| 46 # the function |
| 47 # I have yet to see errors caused by passing 'char' to isspace and friends |
| 48 "C6330", # 'char' passed as _Param_(1) when 'unsigned char' is required |
| 49 # This warning needs to be in clang to make it effective |
| 50 "C6262", # Function uses too much stack |
| 51 # Triggers on isnan, isinf, and template metaprogramming. |
| 52 "C6334", # sizeof operator applied to an expression with an operator might |
| 53 # yield unexpected results: |
| 54 ] |
| 55 |
| 56 warningRe = re.compile(r"(.*)\(\d+\) : warning (C\d{4,5}): (.*)") |
| 57 warningRefLine = re.compile(r"(.*line ')\d+('.*)") |
| 58 warningRefLine2 = re.compile(r"(.*line )\d+(:.*)") |
| 59 |
| 60 def RemoveExtraneous(line): |
| 61 """ |
| 62 Remove extraneous data such as the optional 'Lines:' block at the end of some |
| 63 warnings, and line ending characters. |
| 64 This ensures better matching and makes for less cluttered results. |
| 65 """ |
| 66 linesOffset = line.find(": Lines:") |
| 67 if linesOffset >= 0: |
| 68 line = line[:linesOffset] |
| 69 return line.strip() |
| 70 |
| 71 |
| 72 |
| 73 def SummarizeWarnings(filename): |
| 74 """ |
| 75 This function reads the file and looks for warning messages. It creates a |
| 76 dictionary with the keys being the filename, warning number, and warning text, |
| 77 and returns this. |
| 78 The warning summary at the end is ignored because it doesn't match the regex |
| 79 due to the 'C' being stripped from the warnings, for just this purpose. |
| 80 """ |
| 81 warnings = {} |
| 82 for line in open(filename).readlines(): |
| 83 line = line.replace(r"\chromium\src", r"\analyze_chromium\src") |
| 84 line = line.replace(r"\chromium2\src", r"\analyze_chromium\src") |
| 85 line = RemoveExtraneous(line) |
| 86 match = warningRe.match(line) |
| 87 if match: |
| 88 file, warningNumber, description = match.groups() |
| 89 ignore = False |
| 90 if warningNumber in warningsToIgnore: |
| 91 ignore = True |
| 92 glesTest = "gles2_implementation_unittest" |
| 93 if warningNumber == "C6001" and line.count(glesTest) > 0: |
| 94 ignore = True # Many spurious warnings of this form |
| 95 if not ignore: |
| 96 # See if the description contains line numbers, so that we can |
| 97 # remove them. |
| 98 matchLine = warningRefLine.match(description) |
| 99 if not matchLine: |
| 100 matchLine = warningRefLine2.match(description) |
| 101 if matchLine: |
| 102 # Replace referenced line numbers with #undef so that they don't cause |
| 103 # mismatches. |
| 104 description = "#undef".join(matchLine.groups()) |
| 105 # Look for "the readable size is " and "the writable size is " because |
| 106 # these are often followed by sizes that vary in uninteresting ways, |
| 107 # especially between 32-bit and 64-bit builds. |
| 108 readableText = "the readable size is " |
| 109 writableText = "the writable size is " |
| 110 if description.find(readableText) >= 0: |
| 111 description = description[:description.find(readableText)] |
| 112 if description.find(writableText) >= 0: |
| 113 description = description[:description.find(writableText)] |
| 114 |
| 115 key = (file, warningNumber, description) |
| 116 if not key in warnings: |
| 117 warnings[key] = [] |
| 118 warnings[key].append(line.strip()) |
| 119 return warnings |
| 120 |
| 121 |
| 122 |
| 123 def PrintAdditions(oldResults, newResults, message, invert): |
| 124 results = [] |
| 125 for key in newResults.keys(): |
| 126 if oldResults.has_key(key): |
| 127 # Check to see if the warning count has changed |
| 128 old = oldResults[key] |
| 129 new = newResults[key] |
| 130 if len(new) > len(old): |
| 131 # If the warning count has increased then we don't know which ones are |
| 132 # new. Sigh... Report the new ones, up to some maximum: |
| 133 for warning in newResults[key]: |
| 134 if invert: |
| 135 results.append(warning + ": count went from %d to %d" % \ |
| 136 (len(newResults[key]), len(oldResults[key]))) |
| 137 else: |
| 138 results.append(warning + ": count went from %d to %d" % \ |
| 139 (len(oldResults[key]), len(newResults[key]))) |
| 140 else: |
| 141 # Totally new (or fixed) warning. |
| 142 results += newResults[key] |
| 143 # This sort is not perfect because it is alphabetic and it needs to switch to |
| 144 # numeric when it encounters digits. Later. |
| 145 results.sort() |
| 146 print "%s (%d total)" % (message, len(results)) |
| 147 for line in results: |
| 148 print line |
| 149 |
| 150 |
| 151 |
| 152 if len(sys.argv) < 3: |
| 153 print "Usage: %s oldsummary.txt newsummary.txt" % sys.argv[0] |
| 154 print "Prints the changes in warnings between two /analyze runs." |
| 155 sys.exit(0) |
| 156 |
| 157 oldFilename = sys.argv[1] |
| 158 newFilename = sys.argv[2] |
| 159 oldResults = SummarizeWarnings(oldFilename) |
| 160 newResults = SummarizeWarnings(newFilename) |
| 161 |
| 162 PrintAdditions(oldResults, newResults, "New warnings", False) |
| 163 print |
| 164 print |
| 165 PrintAdditions(newResults, oldResults, "Fixed warnings", True) |
| OLD | NEW |