inspect.lua 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. -- base class for all inspectors
  2. -- every derived class must implement inspect()
  3. class 'inspector'
  4. function inspector:__init(name)
  5. self.name = name
  6. self.warnings = {}
  7. end
  8. function inspector:warning(path, str)
  9. table.insert( self.warnings, { path, str } )
  10. end
  11. function inspector:report()
  12. local output = function(_,x)
  13. local name = x[1]:string()
  14. print(name .. ": " .. x[2])
  15. end
  16. local cmp = function(a,b)
  17. return a[1]:string() < b[1]:string()
  18. end
  19. local violations
  20. if table.getn(self.warnings) ~= 0 then
  21. violations = table.getn(self.warnings) .. " violations"
  22. else
  23. violations = "no violations"
  24. end
  25. print("\n-- " .. self.name .. " [" .. violations .. "]\n")
  26. table.sort(self.warnings, cmp)
  27. table.foreach(self.warnings, output)
  28. end
  29. inspector.inspect = nil
  30. -- checks filename length
  31. class 'filename_length' (inspector)
  32. function filename_length:__init(n)
  33. super("filename length (" .. n .. " characters)")
  34. self.maxlen = n
  35. end
  36. function filename_length:inspect(path)
  37. local n = string.len(path:leaf())
  38. if n > self.maxlen then
  39. self:warning(path, n .. " characters in filename")
  40. end
  41. end
  42. -- checks that the filename is all lowercase
  43. class 'filename_case' (inspector)
  44. function filename_case:__init()
  45. super("filename case")
  46. end
  47. function filename_case:inspect(path)
  48. if string.lower(path:leaf()) ~= path:leaf() then
  49. self:warning(path, "uppercase letters")
  50. end
  51. end
  52. -- checks that the file doesn't contain tabs
  53. class 'tab_inspector' (inspector)
  54. function tab_inspector:__init()
  55. super("tab inspector")
  56. end
  57. function tab_inspector:inspect(path)
  58. if has_endings(path:leaf(), ".hpp", ".cpp") then
  59. for line in io.lines(path:string()) do
  60. if string.find(line, '\t') ~= nil then
  61. self:warning(path, "tabs in file")
  62. return
  63. end
  64. end
  65. end
  66. end
  67. -- checks that the file doesn't contain too long lines
  68. class 'line_length_inspector' (inspector)
  69. function line_length_inspector:__init(n)
  70. super("line length inspector (" .. n .. " characters)")
  71. self.maxlen = n
  72. end
  73. function line_length_inspector:inspect(path)
  74. if has_endings(path:leaf(), ".hpp", ".cpp") then
  75. for line in io.lines(path:string()) do
  76. if string.len(line) > self.maxlen then
  77. self:warning(path, "lines too long " .. string.len(line))
  78. return
  79. end
  80. end
  81. end
  82. end
  83. -- checks for unmatched #define/#undef pairs
  84. class 'define_inspector' (inspector)
  85. function define_inspector:__init()
  86. super("define inspector")
  87. end
  88. function define_inspector:inspect(path)
  89. if has_endings(path:leaf(), ".hpp") then
  90. local defs = {}
  91. for line in io.lines(path:string()) do
  92. local pos, _, def = string.find(line, "#%s*define%s+([%w_]+)")
  93. if pos ~= nil then defs[def] = true end
  94. local pos, _, def = string.find(line, "#%s*undef%s+([%w_]+)")
  95. if pos ~= nil then defs[def] = nil end
  96. end
  97. table.foreach(defs, function(def)
  98. self:warning(path, def)
  99. end)
  100. end
  101. end
  102. -- helper functions
  103. function file_ending(name)
  104. local pos = string.find(name, "%.")
  105. if pos == nil then return ""
  106. else
  107. return string.sub(name, pos)
  108. end
  109. end
  110. function has_endings(name, ...)
  111. local ending = file_ending(name)
  112. for _,i in arg do
  113. if ending == i then return true end
  114. end
  115. return false
  116. end
  117. function recurse_dir(path)
  118. for i in path.contents do
  119. if i:is_directory() then recurse_dir(i)
  120. else
  121. table.foreach(inspectors, function(_,x)
  122. x:inspect(i)
  123. end)
  124. number_of_files = number_of_files + 1
  125. end
  126. end
  127. end
  128. -- main
  129. inspectors = { filename_length(31), filename_case(),
  130. tab_inspector(), line_length_inspector(79),
  131. define_inspector() }
  132. number_of_files = 0
  133. if args.n >= 3 then root = filesystem.path(args[3])
  134. else root = filesystem.initial_path() end
  135. print("inspecting '" .. root:string() .. "' ...")
  136. recurse_dir(root)
  137. print(" ** " .. number_of_files .. " files was inspected")
  138. table.foreach(inspectors, function(_,i)
  139. i:report()
  140. end)