warn_fix.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. import sys
  9. import json
  10. import os
  11. import re
  12. import subprocess
  13. import argparse
  14. warnre = re.compile(r'(.*)\((\d*),(\d*)\): warning C(\d+): (.*)')
  15. w4100_message_lambda = re.compile(r'.*\'(.*)\'.*')
  16. # will contain a dictionary<filename, dictionary<linenumber, dictionary<column, warningcode>>>
  17. all_warnings = dict()
  18. def fix_debug_wrap(fix_function, warningNumber, fileLines, lineNumber, columnNumber, message):
  19. print('Input: ')
  20. print(fileLines[lineNumber].rstrip())
  21. print(' ' * (columnNumber-1) + f'^ w{warningNumber}')
  22. ret = fix_function(fileLines, lineNumber, columnNumber, message)
  23. if ret:
  24. print('Output: ')
  25. print(fileLines[lineNumber].rstrip())
  26. else:
  27. print('Unmodified')
  28. return ret
  29. def fix_4100(fileLines, lineNumber, columnNumber, message):
  30. line = fileLines[lineNumber]
  31. startColumn = columnNumber-1
  32. lastNonSpacePosition = startColumn
  33. for colIndex in range(startColumn, 0, -1):
  34. if line[colIndex] in (',', '('):
  35. fileLines[lineNumber] = line[:colIndex+1] + ('',' ')[line[colIndex] == ','] + '[[maybe_unused]]' + ('',' ')[line[colIndex] == '('] + line[colIndex+1:]
  36. return True
  37. if line[colIndex] not in (' ', '\t'):
  38. lastNonSpacePosition = colIndex
  39. if lastNonSpacePosition < (startColumn-1): # cases where the parameter is in a new line
  40. fileLines[lineNumber] = line[:lastNonSpacePosition] + '[[maybe_unused]] ' + line[lastNonSpacePosition:]
  41. return True
  42. # This warning is also issued for lambdas, but in the lambda case, the warning points to the end of the lambda
  43. if line[columnNumber-1] == '}': # lambda case
  44. reResult = w4100_message_lambda.search(message)
  45. if reResult:
  46. variable = ' ' + reResult.group(1)
  47. # Now search lines above. Since the variable is not used in the lambda, we can iterate until we find it
  48. for lineIndex in range(lineNumber-1, 0, -1):
  49. col = fileLines[lineIndex].find(variable)
  50. if col != -1:
  51. return fix_4100(fileLines, lineIndex, col, message)
  52. return False
  53. def fix_4189(fileLines, lineNumber, columnNumber, message):
  54. del fileLines[lineNumber]
  55. return True
  56. warning_fixers = dict()
  57. warning_fixers[4100] = fix_4100
  58. warning_fixers[4189] = fix_4189
  59. def loadBuildLog(build_log):
  60. try:
  61. with open(build_log, 'r') as log_file:
  62. try:
  63. logLines = log_file.readlines()
  64. except UnicodeDecodeError as err:
  65. print('Error reading file {}, err: {}'.format(input_file, err))
  66. return
  67. except IOError as err:
  68. print('Error opening {}: {}'.format(input_file, err))
  69. return
  70. for logLine in logLines:
  71. reResult = warnre.search(logLine)
  72. if reResult:
  73. filename = os.path.abspath(reResult.group(1))
  74. lineNumber = int(reResult.group(2))
  75. columnNumber = int(reResult.group(3))
  76. warningNumber = int(reResult.group(4))
  77. message = reResult.group(5)
  78. (all_warnings.setdefault(filename, dict())
  79. .setdefault(lineNumber, dict())
  80. .setdefault(columnNumber, dict())
  81. .setdefault(warningNumber, message))
  82. def processWarnings():
  83. for filename, filename_warnings in all_warnings.items(): # file sorting irrelevant
  84. with open(filename, 'r') as read_file:
  85. try:
  86. fileLines = read_file.readlines()
  87. except UnicodeDecodeError as err:
  88. print('Error reading file {}, err: {}'.format(input_file, err))
  89. continue
  90. hasEdit = False
  91. for lineNumber, line_warnings in sorted(filename_warnings.items(), reverse=True): # Invert line number ordering to start from the bottom
  92. for columnNumber, column_warnings in sorted(line_warnings.items(), reverse=True): # Invert column number odering to start from the right
  93. for warningNumber, message in column_warnings.items(): # warning sorting irrelevant
  94. if warningNumber in warning_fixers.keys():
  95. #edited = fix_debug_wrap(warning_fixers[warningNumber], warningNumber, fileLines, lineNumber-1, columnNumber, message)
  96. edited = warning_fixers[warningNumber](fileLines, lineNumber-1, columnNumber, message)
  97. if not edited:
  98. print(f'unfixed w{warningNumber}: {filename}({lineNumber},{columnNumber})')
  99. hasEdit |= edited
  100. if hasEdit:
  101. # p4 edit the file
  102. # subprocess.check_call(['p4', 'edit', filename])
  103. with open(filename, 'w') as destination_file:
  104. destination_file.writelines(fileLines)
  105. # Stop during debugging
  106. #break
  107. def main():
  108. """script main function"""
  109. parser = argparse.ArgumentParser(description='This script fixes warnings in msvc builds',
  110. formatter_class=argparse.RawTextHelpFormatter)
  111. parser.add_argument('build_log', type=str,
  112. help='file with the build output')
  113. args = parser.parse_args()
  114. loadBuildLog(args.build_log)
  115. processWarnings()
  116. #entrypoint
  117. if __name__ == '__main__':
  118. main()