##// END OF EJS Templates
Ajout de vera++
perrinel -
r2:451739a45362
parent child
Show More
@@ -0,0 +1,52
1 # - try to find vera++ tool
2 #
3 # Cache Variables:
4 # VERA++_ROOT_DIR
5 # VERA++_EXECUTABLE
6 # VERA++_USE_FILE
7 #
8 # Non-cache variables you might use in your CMakeLists.txt:
9 # VERA++_FOUND
10 #
11 # Requires these CMake modules:
12 # FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
13
14 file(TO_CMAKE_PATH "${VERA++_ROOT_DIR}" VERA++_ROOT_DIR)
15 set(VERA++_ROOT_DIR
16 "${VERA++_ROOT_DIR}"
17 CACHE
18 PATH
19 "Path to search for vera++")
20
21 if(VERA++_EXECUTABLE AND NOT EXISTS "${VERA++_EXECUTABLE}")
22 set(VERA++_EXECUTABLE "notfound" CACHE PATH FORCE "")
23 endif()
24
25 # If we have a custom path, look there first.
26 if(VERA++_ROOT_DIR)
27 find_program(VERA++_EXECUTABLE
28 NAMES
29 vera++
30 PATHS
31 "${VERA++_ROOT_DIR}"
32 PATH_SUFFIXES
33 bin
34 NO_DEFAULT_PATH)
35 endif()
36
37 find_program(VERA++_EXECUTABLE NAMES vera++)
38
39 # Find the use file for vera
40 GET_FILENAME_COMPONENT(VERA++_MODULE_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
41 SET(VERA++_USE_FILE "${VERA++_MODULE_DIR}/use_vera++.cmake")
42
43 SET(VERA++_ALL ${VERA++_EXECUTABLE} ${VERA++_USE_FILE})
44
45 include(FindPackageHandleStandardArgs)
46 find_package_handle_standard_args(vera++
47 DEFAULT_MSG
48 VERA++_ALL
49 VERA++_EXECUTABLE
50 VERA++_USE_FILE)
51
52 mark_as_advanced(VERA++_EXECUTABLE)
@@ -0,0 +1,342
1 #
2 # use_vera++.cmake
3 #
4 # The following functions are defined in this document:
5 # - ADD_VERA_TARGETS
6 # - ADD_VERA_CHECKSTYLE_TARGET
7 #
8
9 # ADD_VERA_TARGETS(<globExpression> ...
10 # [ADD_TO_ALL]
11 # [NAME <name>]
12 # [NAME_ALL <nameall>]
13 # [ROOT <directory>]
14 # [PROFILE <profile>]
15 # [RECURSE]
16 # [EXCLUSION <exclusionFile> ...]
17 # [PARAMETER <name>=<value> ...]
18 # [PARAMETERFILE <parameterFile> ...])
19 #
20 # Two custom targets will be created:
21 # * style_reports is run as part of the build, and is not rerun unless one of
22 # the file checked is modified (only created if ADD_TO_ALL is provided);
23 # * style must be explicitely called (make style) and is rerun even if the files
24 # to check have not been modified. To achieve this behavior, the commands used
25 # in this target pretend to produce a file without actually producing it.
26 # Because the output file is not there after the run, the command will be rerun
27 # again at the next target build.
28 # The report style is selected based on the build environment, so the style
29 # problems are properly reported in the IDEs
30 #
31 # If ADD_TO_ALL is provided then a target will be added to the default build
32 # targets so that each time a source file is compiled, it is analyzed with
33 # vera++.
34 #
35 # NAME and NAME_ALL customize the name of the targets (style and style_reports
36 # by default respectively).
37 #
38 # ROOT set the vera++ root directory, containing the rules and profiles (default
39 # to the current binary directory).
40 #
41 # PROFILE selects the vera++ profile to use (default to "default").
42 #
43 # RECURSE selects if the glob expressions should be applied recursively or not.
44 #
45 # EXCLUSION list of vera++ exclusion files. Can be used several times.
46 #
47 # PARAMETER list of vera++ parameters (name=value). Can be used several times.
48 #
49 # PARAMETERFILE list of vera++ parameter files. Can be used several times.
50 function(add_vera_targets)
51 # default values
52 set(target "style")
53 set(target_all "style_reports")
54 set(profile "default")
55 set(root "${CMAKE_CURRENT_BINARY_DIR}")
56 set(exclusions)
57 set(parameters)
58 set(parameterFiles)
59 set(recurse OFF)
60 set(addToAll OFF)
61 set(globs)
62 # parse the options
63 math(EXPR lastIdx "${ARGC} - 1")
64 set(i 0)
65 while(i LESS ${ARGC})
66 set(arg "${ARGV${i}}")
67 if("${arg}" STREQUAL "ADD_TO_ALL")
68 set(addToAll ON)
69 elseif("${arg}" STREQUAL "NAME")
70 vera_incr(i)
71 set(target "${ARGV${i}}")
72 elseif("${arg}" STREQUAL "NAME_ALL")
73 vera_incr(i)
74 set(target_all "${ARGV${i}}")
75 elseif("${arg}" STREQUAL "ROOT")
76 vera_incr(i)
77 set(root "${ARGV${i}}")
78 elseif("${arg}" STREQUAL "PROFILE")
79 vera_incr(i)
80 set(profile "${ARGV${i}}")
81 elseif("${arg}" STREQUAL "EXCLUSION")
82 vera_incr(i)
83 list(APPEND exclusions --exclusions "${ARGV${i}}")
84 elseif("${arg}" STREQUAL "RECURSE")
85 set(recurse ON)
86 elseif("${arg}" STREQUAL "PARAMETER")
87 vera_incr(i)
88 list(APPEND parameters --parameter "${ARGV${i}}")
89 elseif("${arg}" STREQUAL "PARAMETERFILE")
90 vera_incr(i)
91 list(APPEND parameterFiles --parameters "${ARGV${i}}")
92 else()
93 list(APPEND globs ${arg})
94 endif()
95 vera_incr(i)
96 endwhile()
97
98 if(recurse)
99 file(GLOB_RECURSE srcs ${globs})
100 else()
101 file(GLOB srcs ${globs})
102 endif()
103 list(SORT srcs)
104
105 if(NOT VERA++_EXECUTABLE AND TARGET vera)
106 set(vera_program "$<TARGET_FILE:vera>")
107 else()
108 set(vera_program "${VERA++_EXECUTABLE}")
109 endif()
110
111 # Two custom targets will be created:
112 # * style_reports is run as part of the build, and is not rerun unless one of
113 # the file checked is modified;
114 # * style must be explicitely called (make style) and is rerun even if the files
115 # to check have not been modified. To achieve this behavior, the commands used
116 # in this target pretend to produce a file without actually producing it.
117 # Because the output file is not there after the run, the command will be rerun
118 # again at the next target build.
119 # The report style is selected based on the build environment, so the style
120 # problems are properly reported in the IDEs
121 if(MSVC)
122 set(style vc)
123 else()
124 set(style std)
125 endif()
126 set(xmlreports)
127 set(noreports)
128 set(reportNb 0)
129 set(reportsrcs)
130 list(GET srcs 0 first)
131 get_filename_component(currentDir ${first} PATH)
132 # add a fake src file in a fake dir to trigger the creation of the last
133 # custom command
134 list(APPEND srcs "#12345678900987654321#/0987654321#1234567890")
135 # Create the directory where the reports will be saved
136 SET(reportDirectory "${CMAKE_CURRENT_BINARY_DIR}/vera")
137 FILE(MAKE_DIRECTORY ${reportDirectory})
138 foreach(s ${srcs})
139 get_filename_component(d ${s} PATH)
140 if(NOT "${d}" STREQUAL "${currentDir}")
141 # this is a new dir - lets generate everything needed for the previous dir
142 string(LENGTH "${CMAKE_SOURCE_DIR}" len)
143 string(SUBSTRING "${currentDir}" 0 ${len} pre)
144 if("${pre}" STREQUAL "${CMAKE_SOURCE_DIR}")
145 string(SUBSTRING "${currentDir}" ${len} -1 currentDir)
146 string(REGEX REPLACE "^/" "" currentDir "${currentDir}")
147 endif()
148 if("${currentDir}" STREQUAL "")
149 set(currentDir ".")
150 endif()
151 set(xmlreport ${reportDirectory}/vera_report_${reportNb}.xml)
152 if(addToAll)
153 add_custom_command(
154 OUTPUT ${xmlreport}
155 COMMAND ${vera_program}
156 --root ${root}
157 --profile ${profile}
158 --${style}-report=-
159 --show-rule
160 --warning
161 --xml-report=${xmlreport}
162 ${exclusions}
163 ${parameters}
164 ${parameterFiles}
165 ${reportsrcs}
166 DEPENDS ${reportsrcs}
167 COMMENT "Checking style with vera++ in ${currentDir}"
168 )
169 endif()
170
171 set(noreport ${reportDirectory}/vera_noreport_${reportNb}.xml)
172 add_custom_command(
173 OUTPUT ${noreport}
174 COMMAND ${vera_program}
175 --root ${root}
176 --profile ${profile}
177 --${style}-report=-
178 --show-rule
179 --warning
180 # --xml-report=${noreport}
181 ${exclusions}
182 ${parameters}
183 ${parameterFiles}
184 ${reportsrcs}
185 DEPENDS ${reportsrcs}
186 COMMENT "Checking style with vera++ in ${currentDir}"
187 )
188
189 list(APPEND xmlreports ${xmlreport})
190 list(APPEND noreports ${noreport})
191 vera_incr(reportNb)
192 # clear the list for the next dir
193 set(reportsrcs)
194 set(currentDir ${d})
195 endif()
196 list(APPEND reportsrcs ${s})
197 endforeach()
198 # Create the custom targets that will trigger the custom command created
199 # previously
200 if(addToAll)
201 add_custom_target(${target_all} ALL DEPENDS ${xmlreports})
202 endif()
203 add_custom_target(${target} DEPENDS ${noreports})
204 endfunction()
205
206
207 # ADD_VERA_CHECKSTYLE_TARGET(<globExpression> ...
208 # [NAME <name>]
209 # [ROOT <directory>]
210 # [PROFILE <profile>]
211 # [RECURSE]
212 # [EXCLUSION <exclusionFile> ...]
213 # [PARAMETER <name>=<value> ...]
214 # [PARAMETERFILE <parameterFile> ...])
215 #
216 # The checkstyle custom target will be created. This target runs vera++ and
217 # create checkstyle reports in the ${CMAKE_CURRENT_BINARY_DIR}/checkstyle
218 # directory.
219 #
220 # NAME customize the name of the target (checkstyle by default).
221 #
222 # ROOT set the vera++ root directory, containing the rules and profiles (default
223 # to the current binary directory).
224 #
225 # PROFILE selects the vera++ profile to use (default to "default").
226 #
227 # RECURSE selects if the glob expressions should be applied recursively or not.
228 #
229 # EXCLUSION list of vera++ exclusion files. Can be used several times.
230 #
231 # PARAMETER list of vera++ parameters (name=value). Can be used several times.
232 #
233 # PARAMETERFILE list of vera++ parameter files. Can be used several times.
234 function(add_vera_checkstyle_target)
235 # default values
236 set(target "checkstyle")
237 set(profile "default")
238 set(root "${CMAKE_CURRENT_BINARY_DIR}")
239 set(exclusions)
240 set(parameters)
241 set(parameterFiles)
242 set(recurse OFF)
243 set(globs)
244 # parse the options
245 math(EXPR lastIdx "${ARGC} - 1")
246 set(i 0)
247 while(i LESS ${ARGC})
248 set(arg "${ARGV${i}}")
249 if("${arg}" STREQUAL "NAME")
250 vera_incr(i)
251 set(target "${ARGV${i}}")
252 elseif("${arg}" STREQUAL "ROOT")
253 vera_incr(i)
254 set(root "${ARGV${i}}")
255 elseif("${arg}" STREQUAL "PROFILE")
256 vera_incr(i)
257 set(profile "${ARGV${i}}")
258 elseif("${arg}" STREQUAL "EXCLUSION")
259 vera_incr(i)
260 list(APPEND exclusions --exclusions "${ARGV${i}}")
261 elseif("${arg}" STREQUAL "RECURSE")
262 set(recurse ON)
263 elseif("${arg}" STREQUAL "PARAMETER")
264 vera_incr(i)
265 list(APPEND parameters --parameter "${ARGV${i}}")
266 elseif("${arg}" STREQUAL "PARAMETERFILE")
267 vera_incr(i)
268 list(APPEND parameterFiles --parameters "${ARGV${i}}")
269 else()
270 list(APPEND globs ${arg})
271 endif()
272 vera_incr(i)
273 endwhile()
274
275 if(recurse)
276 file(GLOB_RECURSE srcs ${globs})
277 else()
278 file(GLOB srcs ${globs})
279 endif()
280 list(SORT srcs)
281
282 if(NOT VERA++_EXECUTABLE AND TARGET vera)
283 set(vera_program "$<TARGET_FILE:vera>")
284 else()
285 set(vera_program "${VERA++_EXECUTABLE}")
286 endif()
287
288 set(checkstylereports)
289 set(reportNb 0)
290 set(reportsrcs)
291 list(GET srcs 0 first)
292 get_filename_component(currentDir ${first} PATH)
293 # add a fake src file in a fake dir to trigger the creation of the last
294 # custom command
295 list(APPEND srcs "#12345678900987654321#/0987654321#1234567890")
296 # Create the directory where the reports will be saved
297 SET(checkstyleDirectory "${CMAKE_CURRENT_BINARY_DIR}/checkstyle")
298 FILE(MAKE_DIRECTORY ${checkstyleDirectory})
299 foreach(s ${srcs})
300 get_filename_component(d ${s} PATH)
301 if(NOT "${d}" STREQUAL "${currentDir}")
302 # this is a new dir - lets generate everything needed for the previous dir
303 string(LENGTH "${CMAKE_SOURCE_DIR}" len)
304 string(SUBSTRING "${currentDir}" 0 ${len} pre)
305 if("${pre}" STREQUAL "${CMAKE_SOURCE_DIR}")
306 string(SUBSTRING "${currentDir}" ${len} -1 currentDir)
307 string(REGEX REPLACE "^/" "" currentDir "${currentDir}")
308 endif()
309 if("${currentDir}" STREQUAL "")
310 set(currentDir ".")
311 endif()
312 set(checkstylereport ${checkstyleDirectory}/vera_checkstylereport_${reportNb}.xml)
313 add_custom_command(
314 OUTPUT ${checkstylereport}
315 COMMAND ${vera_program}
316 --root ${root}
317 --profile ${profile}
318 --show-rule
319 --checkstyle-report ${checkstylereport}
320 ${exclusions}
321 ${parameters}
322 ${parameterFiles}
323 ${reportsrcs}
324 DEPENDS ${reportsrcs}
325 COMMENT "Checking style with vera++ in ${currentDir}"
326 )
327 list(APPEND checkstylereports ${checkstylereport})
328 vera_incr(reportNb)
329 # clear the list for the next dir
330 set(reportsrcs)
331 set(currentDir ${d})
332 endif()
333 list(APPEND reportsrcs ${s})
334 endforeach()
335 # Create the custom targets that will trigger the custom command created
336 # previously
337 add_custom_target(${target} DEPENDS ${checkstylereports})
338 endfunction()
339
340 macro(vera_incr var_name)
341 math(EXPR ${var_name} "${${var_name}} + 1")
342 endmacro()
@@ -0,0 +1,26
1 #!/usr/bin/tclsh
2 # This file defines the set of scripts (rules) that should be executed
3 # by default (if no specific profile is named when vera++ is launched).
4
5 set rules {
6 IPSIS_F11
7 IPSIS_F13
8
9 IPSIS_S01
10 IPSIS_S02
11 IPSIS_S03
12 IPSIS_S04_FILENAME
13 IPSIS_S04_NAMESPACE
14 IPSIS_S04_CLASS
15 IPSIS_S04_ENUM
16 IPSIS_S04_TYPEDEF
17 IPSIS_S04_METHOD
18 IPSIS_S04_VARIABLE
19 IPSIS_S05
20 IPSIS_S06
21 IPSIS_S09
22
23 IPSIS_C01
24 IPSIS_C09
25 IPSIS_C11
26 }
@@ -0,0 +1,26
1 #!/usr/bin/tclsh
2 # This file defines the set of scripts (rules) that should be executed for a
3 # default IPSIS project.
4
5 set rules {
6 IPSIS_F11
7 IPSIS_F13
8
9 IPSIS_S01
10 IPSIS_S02
11 IPSIS_S03
12 IPSIS_S04_FILENAME
13 IPSIS_S04_NAMESPACE
14 IPSIS_S04_CLASS
15 IPSIS_S04_ENUM
16 IPSIS_S04_TYPEDEF
17 IPSIS_S04_METHOD
18 IPSIS_S04_VARIABLE
19 IPSIS_S05
20 IPSIS_S06
21 IPSIS_S09
22
23 IPSIS_C01
24 IPSIS_C09
25 IPSIS_C11
26 }
@@ -0,0 +1,13
1 #!/usr/bin/tclsh
2 foreach f [getSourceFileNames] {
3 puts "Tokens in file ${f}:"
4 foreach t [getTokens $f 1 0 -1 -1 {}] {
5 set value [lindex $t 0]
6 set line [lindex $t 1]
7 set column [lindex $t 2]
8 set name [lindex $t 3]
9
10 puts "${line}/${column}\t${name}\t${value}"
11 }
12 puts ""
13 }
@@ -0,0 +1,65
1 #!/usr/bin/tclsh
2 # The destructor of a class should be virtual
3
4 proc createMachine {initState} {
5 set machine [dict create state $initState bracesCounter 0]
6 return $machine
7 }
8
9 foreach fileName [getSourceFileNames] {
10 set machines [list]
11
12 set prev1 ""
13 set prev2 ""
14 foreach token [getTokens $fileName 1 0 -1 -1 {class struct leftbrace rightbrace virtual compl identifier semicolon}] {
15 set type [lindex $token 3]
16 set line [lindex $token 1]
17
18 if {$type == "class" || $type == "struct"} {
19 lappend machines [createMachine "beforeLeftBrace"]
20 }
21
22 set machinesToKeep [list]
23 foreach m $machines {
24 set keepMachine 1
25 dict with m {
26 if {$state == "beforeLeftBrace"} {
27 if {$type == "leftbrace"} {
28 set state "root"
29 } elseif {$type == "semicolon"} {
30 set keepMachine 0
31 }
32 } elseif {$state == "root"} {
33 if {$prev2 != "virtual" && $prev1 == "compl" && $type == "identifier"} {
34 set dtorName [lindex $token 0]
35 report $fileName $line "The destructor ~${dtorName}() of the class should be virtual"
36 }
37
38 if {$type == "leftbrace"} {
39 incr bracesCounter
40 set state "consumeBraces"
41 } elseif {$type == "rightbrace"} {
42 set keepMachine 0
43 }
44 } elseif {$state == "consumeBraces"} {
45 if {$type == "leftbrace"} {
46 incr bracesCounter
47 } elseif {$type == "rightbrace"} {
48 incr bracesCounter -1
49 if {$bracesCounter == 0} {
50 set state "root"
51 }
52 }
53 }
54 }
55
56 if {$keepMachine} {
57 lappend machinesToKeep $m
58 }
59 }
60 set machines $machinesToKeep
61
62 set prev2 $prev1
63 set prev1 $type
64 }
65 }
@@ -0,0 +1,23
1 #!/usr/bin/tclsh
2 # using namespace are not allowed in header files
3
4 foreach fileName [getSourceFileNames] {
5 set extension [file extension $fileName]
6 if {[lsearch {.h .hh .hpp .hxx .ipp} $extension] != -1} {
7
8 set state "start"
9 foreach token [getTokens $fileName 1 0 -1 -1 {using namespace identifier}] {
10 set type [lindex $token 3]
11
12 if {$state == "using" && $type == "namespace"} {
13 report $fileName $usingLine "using namespace not allowed in header file"
14 }
15
16 if {$type == "using"} {
17 set usingLine [lindex $token 1]
18 }
19
20 set state $type
21 }
22 }
23 }
@@ -0,0 +1,103
1 #!/usr/bin/tclsh
2 # Exceptions should be thrown by value and catched by reference.
3 # Moreover a rethrow must be done with throw;
4
5 proc createThrowMachine {line initState} {
6 set machine [dict create name "throw" keywordLine $line state $initState bracesCounter 0 firstKeyword ""]
7 return $machine
8 }
9
10 proc createCatchMachine {line initState} {
11 set machine [dict create name "catch" keywordLine $line state $initState bracesCounter 0 catchedException ""]
12 return $machine
13 }
14
15 foreach fileName [getSourceFileNames] {
16 set machines [list]
17
18 set lastIdentifier ""
19 set prev1 ""
20 set prev2 ""
21 set prev3 ""
22 foreach token [getTokens $fileName 1 0 -1 -1 {throw catch new leftbrace rightbrace greater and identifier rightparen semicolon}] {
23 set type [lindex $token 3]
24 set line [lindex $token 1]
25
26 if {$type == "identifier"} {
27 set lastIdentifier [lindex $token 0]
28 }
29
30 if {$type == "throw"} {
31 lappend machines [createThrowMachine $line "beforeThrow"]
32 } elseif {$type == "catch"} {
33 lappend machines [createCatchMachine $line "waitingForLeftBrace"]
34 }
35
36 set machinesToKeep [list]
37 foreach m $machines {
38 set keepMachine 1
39 dict with m {
40 if {$name == "throw"} {
41 if {$state == "beforeThrow" && $type == "throw"} {
42 set state "catchFirstKeyword"
43 } elseif {$state == "catchFirstKeyword"} {
44 if {$type == "semicolon"} {
45 # This is a rethrow
46 set keepMachine 0
47 } else {
48 set firstKeyword $type
49 set state "waitForEndOfThrow"
50 }
51 } elseif {$state == "waitForEndOfThrow"} {
52 if {$type == "leftbrace"} {
53 # This is an exception specification
54 set keepMachine 0
55 } elseif {$type == "semicolon"} {
56 # This is a throw, check that the first keyword isn't
57 # new or &
58 if {$firstKeyword == "new" || $firstKeyword == "and"} {
59 report $fileName $keywordLine "Exceptions should be thrown by value. Not allocated with new or dereferenced with &."
60 }
61 set keepMachine 0
62 }
63 }
64 } elseif {$name == "catch"} {
65 if {$state == "waitingForLeftBrace" && $type == "leftbrace"} {
66 set state "insideCatch"
67
68 if {$prev2 == "identifier" && $prev1 == "rightparen"} {
69 set catchedException $lastIdentifier
70
71 if {$prev3 != "and"} {
72 report $fileName $keywordLine "Exceptions should be catched by reference (exception catched: $catchedException)"
73 }
74 }
75 } elseif {$state == "insideCatch"} {
76 if {$type == "leftbrace"} {
77 incr bracesCounter
78 } elseif {$type == "rightbrace"} {
79 if {$bracesCounter > 0} {
80 incr bracesCounter -1
81 } else {
82 set keepMachine 0
83 }
84 } elseif {$prev2 == "throw" && $prev1 == "identifier" && $type == "semicolon"} {
85 if {$lastIdentifier == $catchedException} {
86 report $fileName $line "Exceptions should be rethrown with 'throw;' instead of 'throw ${catchedException};'"
87 }
88 }
89 }
90 }
91 }
92
93 if {$keepMachine} {
94 lappend machinesToKeep $m
95 }
96 }
97 set machines $machinesToKeep
98
99 set prev3 $prev2
100 set prev2 $prev1
101 set prev1 $type
102 }
103 }
@@ -0,0 +1,39
1 #!/usr/bin/tclsh
2 # control structures should have complete curly-braced block of code
3
4 foreach fileName [getSourceFileNames] {
5
6 set state "start"
7 set prev ""
8 foreach token [getTokens $fileName 1 0 -1 -1 {for if while do leftparen rightparen leftbrace rightbrace semicolon}] {
9 set type [lindex $token 3]
10
11 if {$state == "control"} {
12 if {$type == "leftparen"} {
13 incr parenCount
14 } elseif {$type == "rightparen"} {
15 incr parenCount -1
16 if {$parenCount == 0} {
17 set state "expectedblock"
18 }
19 }
20 } elseif {$state == "expectedblock"} {
21 if {$type != "leftbrace"} {
22 set line [lindex $token 1]
23 report $fileName $line "full block {} expected in the control structure"
24 }
25 set state "block"
26 }
27
28 if {$type == "for" || $type == "if"} {
29 set parenCount 0
30 set state "control"
31 } elseif {$type == "do"} {
32 set state "expectedblock"
33 } elseif {$type == "while" && $prev != "rightbrace"} {
34 set parenCount 0
35 set state "control"
36 }
37 set prev $type
38 }
39 }
@@ -0,0 +1,73
1 #!/usr/bin/tclsh
2 # namespace names should be recalled at the end of the namespace
3 # namespace mynamespace {
4 # } // mynamespace
5
6 proc createNamespaceDict {} {
7 return [dict create state "waitingForIdentifier" identifier "" bracesCounter 0]
8 }
9
10 foreach fileName [getSourceFileNames] {
11
12 set namespaces [list]
13
14 foreach token [getTokens $fileName 1 0 -1 -1 {namespace identifier leftbrace rightbrace semicolon cppcomment}] {
15 set type [lindex $token 3]
16
17 set namespacesToKeep [list]
18 foreach n $namespaces {
19 set keepNamespace 1
20 dict with n {
21 if {$state == "waitingForIdentifier" && $type == "identifier"} {
22 set state "waitingForLeftBrace"
23 set identifier [lindex $token 0]
24 } elseif {$state == "waitingForLeftBrace"} {
25 if {$type == "semicolon"} {
26 # Wasn't a namespace, remove the dict
27 set keepNamespace 0
28 } elseif {$type == "leftbrace"} {
29 set bracesCounter 0
30 set state "waitingForRightBrace"
31 }
32 } elseif {$state == "waitingForRightBrace"} {
33 if {$type == "leftbrace"} {
34 incr bracesCounter
35 } elseif {$type == "rightbrace"} {
36 if {$bracesCounter > 0} {
37 incr bracesCounter -1
38 } else {
39 set state "waitingForComment"
40 }
41 }
42 } elseif {$state == "waitingForComment"} {
43 if {$type == "cppcomment"} {
44 set commentValue [lindex $token 0]
45 # Check that the comment report the namespace name
46 if {![regexp "\\m$identifier\\M" $commentValue]} {
47 set line [lindex $token 1]
48 set commentValue [string trim $commentValue]
49 report $fileName $line "The namespace $identifier should have been recalled in the comment here (// $identifier). Comment found: $commentValue"
50 }
51 } else {
52 # There should have been a comment here
53 set line [lindex $token 1]
54 report $fileName $line "The namespace $identifier should have been recalled in a comment here (// $identifier)"
55 }
56 # Namespace processed, remove it from the list
57 set keepNamespace 0
58 }
59 }
60
61 if {$keepNamespace} {
62 lappend namespacesToKeep $n
63 }
64 }
65 set namespaces $namespacesToKeep
66
67 # If the token is a namespace keyword, add a namespace dict for the next
68 # foreach
69 if {$type == "namespace"} {
70 lappend namespaces [createNamespaceDict]
71 }
72 }
73 }
@@ -0,0 +1,60
1 #!/usr/bin/tclsh
2 # At most one class per header file
3
4 foreach fileName [getSourceFileNames] {
5 if {[regexp {(?:\\|/)?([^\\/]+?)\.h$} $fileName matchedExpr expectedClassName]} {
6 set state "waitingForClass"
7 set alreadyOneClass 0
8 set firstClassName ""
9 set bracesCounter 0
10
11 set lastIdentifier ""
12 foreach token [getTokens $fileName 1 0 -1 -1 {class identifier leftbrace rightbrace colon semicolon}] {
13 set type [lindex $token 3]
14
15 if {$type == "identifier"} {
16 set lastIdentifier [lindex $token 0]
17 }
18
19 if {$state == "waitingForClass" && $type == "class"} {
20 set state "waitingForBeginingOfClass"
21 } elseif {$state == "waitingForBeginingOfClass"} {
22 if {$type == "semicolon"} {
23 set state "waitingForClass"
24 } elseif {$type == "leftbrace" || $type == "colon"} {
25 # Check if this is the first class
26 if {$alreadyOneClass} {
27 set line [lindex $token 1]
28 report $fileName $line "At most one public class can be defined in a header file. (class $lastIdentifier found but class $firstClassName already defined)"
29 } else {
30 set alreadyOneClass 1
31 set firstClassName $lastIdentifier
32
33 # Check that the class has the same name than the file
34 if {$lastIdentifier != $expectedClassName} {
35 set line [lindex $token 1]
36 report $fileName $line "The public class should have the same name than the header file. (class $lastIdentifier found but class $expectedClassName expected)"
37 }
38 }
39 if {$type == "leftbrace"} {
40 set state "waitingForEndOfClass"
41 } else {
42 set state "waitingForLeftBrace"
43 }
44 }
45 } elseif {$state == "waitingForLeftBrace" && $type == "leftbrace"} {
46 set state "waitingForEndOfClass"
47 } elseif {$state == "waitingForEndOfClass"} {
48 if {$type == "leftbrace"} {
49 incr bracesCounter
50 } elseif {$type == "rightbrace"} {
51 if {$bracesCounter > 0} {
52 incr bracesCounter -1
53 } else {
54 set state "waitingForClass"
55 }
56 }
57 }
58 }
59 }
60 }
@@ -0,0 +1,45
1 #!/usr/bin/tclsh
2 # The include guards should have the form PROJECT_FILENAME_H
3
4 set projectName [string toupper [getParameter "project-name" "PROJECTNAMENOTFOUND"]]
5
6 foreach fileName [getSourceFileNames] {
7 if {[regexp {(?:\\|/)?([^\\/]+?)\.h$} $fileName matchedExpr fileNameWithoutExt]} {
8 set upperFileName [string toupper $fileNameWithoutExt]
9 set expectedGuard "${projectName}_${upperFileName}_H"
10
11 set state "waitingForIfndef"
12
13 set firstInstruction 1
14 set ifndefLine -1
15 set prev ""
16 foreach token [getTokens $fileName 1 0 -1 -1 {pp_ifndef pp_ifdef pp_if pp_include pp_define pp_undef pp_error pp_pragma pp_endif identifier}] {
17 set type [lindex $token 3]
18 set line [lindex $token 1]
19
20 if {$firstInstruction} {
21 set firstInstruction 0
22 if {$type != "pp_ifndef"} {
23 report $fileName $line "The first preprocessor instruction of a header file should be the include guard of the form PROJECTNAME_FILENAME_H. (expected: $expectedGuard)"
24 break
25 } else {
26 set ifndefLine $line
27 }
28 }
29
30 if {$prev == "pp_ifndef"} {
31 if {$type == "identifier"} {
32 set identifier [lindex $token 0]
33 if {$identifier != $expectedGuard} {
34 report $fileName $ifndefLine "The include guard should have the form PROJECTNAME_FILENAME_H. (Found $identifier, expected $expectedGuard)"
35 }
36 } else {
37 report $fileName $ifndefLine "The first preprocessor instruction of a header file should be the include guard of the form PROJECTNAME_FILENAME_H. (expected: $expectedGuard)"
38 }
39 break
40 }
41
42 set prev $type
43 }
44 }
45 }
@@ -0,0 +1,25
1 #!/usr/bin/tclsh
2 # The macros in header files should begin with the name of the project to avoid
3 # collisions
4
5 set projectName [string toupper [getParameter "project-name" "PROJECTNAMENOTFOUND"]]
6
7 foreach fileName [getSourceFileNames] {
8 if {[regexp {\.h$} $fileName]} {
9
10 set prev ""
11 foreach token [getTokens $fileName 1 0 -1 -1 {pp_define identifier}] {
12 set type [lindex $token 3]
13
14 if {$prev == "pp_define" && $type == "identifier"} {
15 set identifier [lindex $token 0]
16 if {![regexp "^${projectName}.*$" $identifier]} {
17 set line [lindex $token 1]
18 report $fileName $line "The macros in header files should begin with the name of the project to avoid collisions. (project name: $projectName, macro found: $identifier)"
19 }
20 }
21
22 set prev $type
23 }
24 }
25 }
@@ -0,0 +1,124
1 #!/usr/bin/tclsh
2 # Naming conventions for classes and structs
3
4 set classRegex [getParameter "class-regex" {^[A-Z][A-Za-z1-9]*$}]
5 set structRegex [getParameter "struct-regex" {^[A-Z][A-Za-z1-9]*$}]
6
7 proc createMachine {machineName initState} {
8 set machine [dict create name $machineName state $initState identifier "" bracesCounter 0 bracketCounter 0 angleBracketCounter 0]
9
10 return $machine
11 }
12
13 proc isClassMacro {value} {
14 set classMacroRegexp [getParameter "classmacro-regex" {}]
15 set classMacros {
16 "Q_OBJECT"
17 }
18 set isClassMacroByRegexp 0
19 if {[string length $classMacroRegexp] != 0} {
20 set isClassMacroByRegexp [regexp $classMacroRegexp $value]
21 }
22 return [expr ([lsearch $classMacros $value] != -1) || $isClassMacroByRegexp]
23 }
24
25 proc isCppType {type value} {
26 set cppTypes {
27 "bool"
28 "char"
29 "int"
30 "float"
31 "double"
32 "void"
33 "wchart"
34 "identifier"
35 }
36
37 set valueIsClassMacro 0
38 if {$type == "identifier"} {
39 set valueIsClassMacro [isClassMacro $value]
40 }
41
42 return [expr ([lsearch $cppTypes $type] != -1) && !$valueIsClassMacro]
43 }
44
45 set tokenFilter {
46 class
47 struct
48 leftbrace
49 rightbrace
50 semicolon
51 colon
52 identifier
53 comma
54 assign
55 rightparen
56 leftbracket
57 }
58
59 foreach fileName [getSourceFileNames] {
60
61 set machines [list]
62
63 set lastIdentifier ""
64 set lastIdentifier2 ""
65 set prev1 ""
66 set prev2 ""
67 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
68 set type [lindex $token 3]
69 set line [lindex $token 1]
70
71 # Retrieve identifier value
72 if {$type == "identifier"} {
73 set lastIdentifier2 $lastIdentifier
74 set lastIdentifier [lindex $token 0]
75 }
76
77 # If the type is a class or a struct, start a class/struct state machine
78 if {$type == "class"} {
79 lappend machines [createMachine "class" "waitingForIdentifier"]
80 }
81 if {$type == "struct"} {
82 lappend machines [createMachine "struct" "waitingForIdentifier"]
83 }
84
85 set machinesToKeep [list]
86 foreach m $machines {
87 set keepMachine 1
88 dict with m {
89 # class/struct
90 if {$name == "class" || $name == "struct"} {
91 # We retrieve the name of the class when we find a colon or
92 # a leftbrace. We wait for these tokens to avoid the export
93 # macros
94 if {$state == "waitingForIdentifier" && ($type == "colon" || $type == "leftbrace")} {
95 set state "waitingForLeftBrace"
96 set identifier $lastIdentifier
97 }
98
99 if {$state == "waitingForLeftBrace" && $type == "leftbrace"} {
100 if {$name == "class" && ![regexp $classRegex $identifier]} {
101 report $fileName $line "The class names should match the following regex: $classRegex (found: $identifier)"
102 }
103 if {$name == "struct" && ![regexp $structRegex $identifier]} {
104 report $fileName $line "The struct names should match the following regex: $structRegex (found: $identifier)"
105 }
106 }
107
108 if {[lsearch {semicolon leftbrace comma assign rightparen leftbracket} $type] != -1} {
109 # End of the state machine
110 set keepMachine 0
111 }
112 }
113 }
114
115 if {$keepMachine} {
116 lappend machinesToKeep $m
117 }
118 }
119 set machines $machinesToKeep
120
121 set prev2 $prev1
122 set prev1 $type
123 }
124 }
@@ -0,0 +1,41
1 #!/usr/bin/tclsh
2 # Naming conventions for enums
3
4 set enumRegex [getParameter "enum-regex" {^[A-Z][A-Za-z1-9]*$}]
5
6 set tokenFilter {
7 class
8 struct
9 enum
10 typedef
11 identifier
12 leftbrace
13 rightbrace
14 semicolon
15 }
16
17 foreach fileName [getSourceFileNames] {
18
19 set lastIdentifier ""
20 set prev1 ""
21 set prev2 ""
22 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
23 set type [lindex $token 3]
24 set line [lindex $token 1]
25
26 # Retrieve identifier value
27 if {$type == "identifier"} {
28 set lastIdentifier [lindex $token 0]
29 }
30
31 # Check enum
32 if {$prev2 == "enum" && $prev1 == "identifier" && $type == "leftbrace"} {
33 if {![regexp $enumRegex $lastIdentifier]} {
34 report $fileName $line "The enum names should match the following regex: $enumRegex (found: $lastIdentifier)"
35 }
36 }
37
38 set prev2 $prev1
39 set prev1 $type
40 }
41 }
@@ -0,0 +1,13
1 #!/usr/bin/tclsh
2 # Naming conventions for file names
3
4 set fileNameRegex [getParameter "filename-regex" {^[A-Z]\w*$}]
5
6 foreach fileName [getSourceFileNames] {
7 # Check file name
8 if {[regexp {(?:\\|/)?([^\\/]+?)\.(?:h|cpp)$} $fileName matchedExpr fileNameWithoutExt]} {
9 if {![regexp $fileNameRegex $fileNameWithoutExt]} {
10 report $fileName 1 "The file names should match the following regex: $fileNameRegex (found: $fileNameWithoutExt)"
11 }
12 }
13 }
@@ -0,0 +1,152
1 #!/usr/bin/tclsh
2 # Naming conventions for methods
3
4 set methodRegex [getParameter "method-regex" {^[a-z][A-Za-z1-9]*$}]
5
6 proc createMachine {machineName initState} {
7 set machine [dict create name $machineName state $initState identifier "" bracesCounter 0 bracketCounter 0 angleBracketCounter 0]
8 return $machine
9 }
10
11 proc isClassMacro {value} {
12 set classMacroRegexp [getParameter "classmacro-regex" {}]
13 set classMacros {
14 "Q_OBJECT"
15 }
16 set isClassMacroByRegexp 0
17 if {[string length $classMacroRegexp] != 0} {
18 set isClassMacroByRegexp [regexp $classMacroRegexp $value]
19 }
20 return [expr ([lsearch $classMacros $value] != -1) || $isClassMacroByRegexp]
21 }
22
23 proc isCppType {type value} {
24 set cppTypes {
25 "bool"
26 "char"
27 "int"
28 "float"
29 "double"
30 "void"
31 "wchart"
32 "identifier"
33 }
34
35 set valueIsClassMacro 0
36 if {$type == "identifier"} {
37 set valueIsClassMacro [isClassMacro $value]
38 }
39
40 return [expr ([lsearch $cppTypes $type] != -1) && !$valueIsClassMacro]
41 }
42
43 set tokenFilter {
44 namespace
45 class
46 struct
47 leftbrace
48 rightbrace
49 leftparen
50 rightparen
51 less
52 greater
53 semicolon
54 identifier
55 colon_colon
56 assign
57 pp_define
58 bool
59 char
60 int
61 float
62 double
63 void
64 wchart
65 }
66
67 foreach fileName [getSourceFileNames] {
68
69 set machines [list]
70
71 # Check the functions at the root of the file
72 lappend machines [createMachine "method" "root"]
73
74 set lastIdentifier ""
75 set lastIdentifier2 ""
76 set prev1 ""
77 set prev2 ""
78 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
79 set type [lindex $token 3]
80 set line [lindex $token 1]
81
82 # Retrieve identifier value
83 if {$type == "identifier"} {
84 set lastIdentifier2 $lastIdentifier
85 set lastIdentifier [lindex $token 0]
86 }
87
88 # Start a method state machine when coming accross a namespace or a
89 # class/struct
90 if {$type == "namespace" || $type == "class" || $type == "struct"} {
91 lappend machines [createMachine "method" "beforeLeftBrace"]
92 }
93
94 set machinesToKeep [list]
95 foreach m $machines {
96 set keepMachine 1
97 dict with m {
98 # Method
99 if {$name == "method"} {
100 if {$state == "beforeLeftBrace"} {
101 if {$type == "leftbrace"} {
102 set state "root"
103 } elseif {$type == "semicolon"} {
104 set keepMachine 0
105 }
106 } elseif {$state == "root"} {
107 if {[isCppType $prev2 $lastIdentifier2] && $prev1 == "identifier" && $type == "leftparen"} {
108 if {![regexp $methodRegex $lastIdentifier]} {
109 report $fileName $line "The method names should match the following regex: $methodRegex (found: $lastIdentifier)"
110 }
111 } elseif {$type == "leftbrace"} {
112 set state "consumeBraces"
113 incr bracesCounter
114 } elseif {$type == "less"} {
115 set state "consumeAngleBracket"
116 incr angleBracketCounter
117 } elseif {$type == "rightbrace"} {
118 # End of the state machine
119 set keepMachine 0
120 }
121 } elseif {$state == "consumeBraces"} {
122 if {$type == "leftbrace"} {
123 incr bracesCounter
124 } elseif {$type == "rightbrace"} {
125 incr bracesCounter -1
126 if {$bracesCounter == 0} {
127 set state "root"
128 }
129 }
130 } elseif {$state == "consumeAngleBracket"} {
131 if {$type == "less"} {
132 incr angleBracketCounter
133 } elseif {$type == "greater"} {
134 incr angleBracketCounter -1
135 if {$angleBracketCounter == 0} {
136 set state "root"
137 }
138 }
139 }
140 }
141 }
142
143 if {$keepMachine} {
144 lappend machinesToKeep $m
145 }
146 }
147 set machines $machinesToKeep
148
149 set prev2 $prev1
150 set prev1 $type
151 }
152 }
@@ -0,0 +1,49
1 #!/usr/bin/tclsh
2 # Naming conventions for namespaces
3
4 set namespaceRegex [getParameter "namespace-regex" {^[a-z][a-z1-9]*$}]
5
6 proc createMachine {machineName initState} {
7 set machine [dict create name $machineName state $initState identifier "" bracesCounter 0 bracketCounter 0 angleBracketCounter 0]
8 return $machine
9 }
10
11 set tokenFilter {
12 using
13 namespace
14 identifier
15 class
16 struct
17 enum
18 typedef
19 leftbrace
20 rightbrace
21 }
22
23 foreach fileName [getSourceFileNames] {
24
25 set machines [list]
26
27 set lastIdentifier ""
28 set prev1 ""
29 set prev2 ""
30 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
31 set type [lindex $token 3]
32 set line [lindex $token 1]
33
34 # Retrieve identifier value
35 if {$type == "identifier"} {
36 set lastIdentifier [lindex $token 0]
37 }
38
39 # Check namespace
40 if {$prev2 == "namespace" && $prev1 == "identifier" && $type == "leftbrace"} {
41 if {![regexp $namespaceRegex $lastIdentifier]} {
42 report $fileName $line "The namespace names should match the following regex: $namespaceRegex (found: $lastIdentifier)"
43 }
44 }
45
46 set prev2 $prev1
47 set prev1 $type
48 }
49 }
@@ -0,0 +1,87
1 #!/usr/bin/tclsh
2 # Naming conventions for typedefs
3
4 set typedefRegex [getParameter "type-regex" {^[A-Z][A-Za-z1-9]*$}]
5
6 proc createMachine {machineName initState} {
7 set machine [dict create name $machineName state $initState identifier "" bracesCounter 0]
8 return $machine
9 }
10
11 set tokenFilter {
12 typedef
13 leftbrace
14 rightbrace
15 semicolon
16 identifier
17 }
18
19 foreach fileName [getSourceFileNames] {
20
21 set machines [list]
22
23 set lastIdentifier ""
24 set lastIdentifier2 ""
25 set prev1 ""
26 set prev2 ""
27 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
28 set type [lindex $token 3]
29 set line [lindex $token 1]
30
31 # Retrieve identifier value
32 if {$type == "identifier"} {
33 set lastIdentifier2 $lastIdentifier
34 set lastIdentifier [lindex $token 0]
35 }
36
37 # If the type is a typedef, start a typedef state machine
38 if {$type == "typedef"} {
39 lappend machines [createMachine "typedef" "waitingForIdentifier"]
40 }
41
42 set machinesToKeep [list]
43 foreach m $machines {
44 set keepMachine 1
45 dict with m {
46 # typedef
47 if {$name == "typedef"} {
48 if {$state == "waitingForIdentifier"} {
49 if {$type == "leftbrace"} {
50 set state "consumeBraces"
51 incr bracesCounter
52 } elseif {$type == "semicolon"} {
53 if {$prev1 == "identifier"} {
54 # Check identifier
55 if {![regexp $typedefRegex $lastIdentifier]} {
56 report $fileName $line "The typedef names should match the following regex: $typedefRegex (found: $lastIdentifier)"
57 }
58 } else {
59 # Typedef without identifier
60 report $fileName $line "A typedef should have a name"
61 }
62 # End of the state machine
63 set keepMachine 0
64 }
65 } elseif {$state == "consumeBraces"} {
66 if {$type == "leftbrace"} {
67 incr bracesCounter
68 } elseif {$type == "rightbrace"} {
69 incr bracesCounter -1
70 if {$bracesCounter == 0} {
71 set state "waitingForIdentifier"
72 }
73 }
74 }
75 }
76 }
77
78 if {$keepMachine} {
79 lappend machinesToKeep $m
80 }
81 }
82 set machines $machinesToKeep
83
84 set prev2 $prev1
85 set prev1 $type
86 }
87 }
@@ -0,0 +1,351
1 #!/usr/bin/tclsh
2 # Naming conventions for variables
3
4 set localVariableRegex [getParameter "local-var-regex" {^[a-z][A-Za-z1-9]*$}]
5 set classMemberVariableRegex [getParameter "class-member-var-regex" {^m_[A-Z][A-Za-z1-9]*$}]
6 set structMemberVariableRegex [getParameter "struct-member-var-regex" {^[a-z][A-Za-z1-9]*$}]
7 set staticMemberVariableRegex [getParameter "static-member-var-regex" {^s_[A-Z][A-Za-z1-9]*$}]
8 set constVarRegex [getParameter "const-var-regex" {^[A-Z][A-Z1-9_]*$}]
9
10 proc createMachine {machineName initState} {
11 set machine [dict create name $machineName state $initState previousState "" identifier "" bracesCounter 0 bracketCounter 0 angleBracketCounter 0]
12
13 # Specific keys for the "memberVariable" type
14 if {$machineName == "memberVariable"} {
15 dict set machine parenCounter 0
16 dict set machine isStatic 0
17 dict set machine isConst 0
18 dict set machine isVar 1
19 dict set machine isTypedef 0
20 dict set machine isInClass 0
21 dict set machine classOrStruct ""
22 }
23
24 return $machine
25 }
26
27 proc isClassMacro {value} {
28 set classMacroRegexp [getParameter "classmacro-regex" {}]
29 set classMacros {
30 "Q_OBJECT"
31 }
32 set isClassMacroByRegexp 0
33 if {[string length $classMacroRegexp] != 0} {
34 set isClassMacroByRegexp [regexp $classMacroRegexp $value]
35 }
36 return [expr ([lsearch $classMacros $value] != -1) || $isClassMacroByRegexp]
37 }
38
39 proc isCppType {type value} {
40 set cppTypes {
41 "bool"
42 "char"
43 "int"
44 "float"
45 "double"
46 "void"
47 "wchart"
48 "identifier"
49 }
50
51 set valueIsClassMacro 0
52 if {$type == "identifier"} {
53 set valueIsClassMacro [isClassMacro $value]
54 }
55
56 return [expr ([lsearch $cppTypes $type] != -1) && !$valueIsClassMacro]
57 }
58
59 set tokenFilter {
60 using
61 namespace
62 class
63 struct
64 enum
65 typedef
66 pp_define
67 leftbrace
68 rightbrace
69 leftparen
70 rightparen
71 leftbracket
72 rightbracket
73 semicolon
74 colon_colon
75 colon
76 comma
77 dot
78 arrow
79 assign
80 static
81 const
82 identifier
83 bool
84 char
85 int
86 float
87 double
88 void
89 wchart
90 return
91 operator
92 less
93 greater
94 }
95
96 foreach fileName [getSourceFileNames] {
97 set machines [list]
98
99 # Check the functions at the root of the file
100 lappend machines [createMachine "method" "root"]
101
102 # Check static const variables at the root of the file
103 lappend machines [createMachine "memberVariable" "root"]
104
105 set lastIdentifier ""
106 set lastIdentifier2 ""
107 set prev1 ""
108 set prev2 ""
109 set insideFunctionParameters 0
110 set insideFunction 0
111 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
112 set type [lindex $token 3]
113 set line [lindex $token 1]
114
115 # Retrieve identifier value
116 if {$type == "identifier"} {
117 set lastIdentifier2 $lastIdentifier
118 set lastIdentifier [lindex $token 0]
119 }
120
121 if {$type == "namespace"} {
122 # Look for the functions in the namespace to check the local variables
123 lappend machines [createMachine "method" "beforeLeftBrace"]
124 # Check the static const variables inside this namespace
125 lappend machines [createMachine "memberVariable" "beforeLeftBrace"]
126 } elseif {$type == "class" || ($type == "struct" && !$insideFunctionParameters)} {
127 # Look for the functions in the class/struct to check the local variables
128 lappend machines [createMachine "method" "beforeLeftBrace"]
129 # Check the static const variables inside this namespace
130 set m [createMachine "memberVariable" "beforeLeftBrace"]
131 dict set m isInClass 1
132 dict set m classOrStruct $type
133 lappend machines $m
134 }
135
136 set machinesToKeep [list]
137 foreach m $machines {
138 set keepMachine 1
139 dict with m {
140 # Method
141 if {$name == "method"} {
142 if {$state == "beforeLeftBrace"} {
143 if {$type == "leftbrace"} {
144 set state "root"
145 } elseif {$type == "semicolon"} {
146 set keepMachine 0
147 }
148 } elseif {$state == "root"} {
149 if {[isCppType $prev2 $lastIdentifier2] && $prev1 == "identifier" && $type == "leftparen"} {
150 # Check the local variables inside this function
151 set insideFunctionParameters 1
152 set insideFunction 1
153 lappend machinesToKeep [createMachine "localVariable" "beforeLeftBrace"]
154
155 } elseif {$type == "leftbrace"} {
156 set state "consumeBraces"
157 incr bracesCounter
158 } elseif {$type == "rightbrace"} {
159 # End of the state machine
160 set keepMachine 0
161 }
162 } elseif {$state == "consumeBraces"} {
163 if {$type == "leftbrace"} {
164 incr bracesCounter
165 } elseif {$type == "rightbrace"} {
166 incr bracesCounter -1
167 if {$bracesCounter == 0} {
168 set state "root"
169 }
170 }
171 }
172 }
173
174 # Local variables
175 if {$name == "localVariable"} {
176 if {$state == "beforeLeftBrace"} {
177 if {$type == "less"} {
178 set previousState $state
179 set state "consumeAngleBracket"
180 incr angleBracketCounter
181 } elseif {[isCppType $prev2 $lastIdentifier2] && $prev1 == "identifier" && ($type == "comma" || $type == "assign" || $type == "rightparen" || $type == "leftbracket")} {
182 # Check function parameters
183 if {![regexp $localVariableRegex $lastIdentifier]} {
184 report $fileName $line "The method parameter names should match the following regex: $localVariableRegex (found: $lastIdentifier)"
185 }
186 } elseif {$type == "leftbrace"} {
187 set insideFunctionParameters 0
188 set state "root"
189 } elseif {$type == "semicolon"} {
190 # End of the state machine
191 set insideFunctionParameters 0
192 set insideFunction 0
193 set keepMachine 0
194 }
195 } elseif {$state == "root"} {
196 if {$type == "leftbrace"} {
197 incr bracesCounter
198 } elseif {$type == "rightbrace"} {
199 if {$bracesCounter > 0} {
200 incr bracesCounter -1
201 } else {
202 # End of the state machine
203 set insideFunctionParameters 0
204 set insideFunction 0
205 set keepMachine 0
206 }
207 }
208
209 if {[isCppType $prev2 $lastIdentifier2] && $prev1 == "identifier" && ($type == "assign" || $type == "semicolon" || $type == "leftparen" || $type == "leftbracket")} {
210 # Check local variable
211 if {![regexp $localVariableRegex $lastIdentifier]} {
212 report $fileName $line "The local variable names should match the following regex: $localVariableRegex (found: $lastIdentifier)"
213 }
214 }
215 } elseif {$state == "consumeBracket"} {
216 if {$type == "leftbracket"} {
217 incr bracketCounter
218 } elseif {$type == "rightbracket"} {
219 incr bracketCounter -1
220 if {$bracketCounter == 0} {
221 set state $previousState
222 }
223 }
224 } elseif {$state == "consumeAngleBracket"} {
225 if {$type == "less"} {
226 incr angleBracketCounter
227 } elseif {$type == "greater"} {
228 incr angleBracketCounter -1
229 if {$angleBracketCounter == 0} {
230 set state $previousState
231 }
232 }
233 }
234
235 if {$state != "consumeBracket" && $type == "leftbracket"} {
236 set previousState $state
237 set state "consumeBracket"
238 incr bracketCounter
239 }
240 }
241
242 # Member and const variables
243 if {$name == "memberVariable"} {
244 if {$state == "beforeLeftBrace"} {
245 if {$type == "leftbrace"} {
246 set state "root"
247 } elseif {$type == "semicolon"} {
248 set keepMachine 0
249 }
250 } elseif {$state == "root"} {
251 # is/isn't var
252 if {$type == "using" || $type == "class" || $type == "struct"} {
253 set isVar 0
254 } elseif {$type == "typedef"} {
255 set isTypedef 1
256 }
257
258 # static/const
259 if {$type == "static"} {
260 set isStatic 1
261 } elseif {$type == "const"} {
262 set isConst 1
263 }
264
265 if {$isVar && !$isTypedef && $prev1 == "pp_define" && $type == "identifier"} {
266 # Check defines
267 if {![regexp $constVarRegex $lastIdentifier]} {
268 report $fileName $line "The constant names should match the following regex: $constVarRegex (found: $lastIdentifier)"
269 }
270 } elseif {$isVar && !$isTypedef && $prev1 == "identifier" && ($type == "assign" || $type == "semicolon" || $type == "leftbracket")} {
271 # Check member variables
272 # Appart from the const, we don't check the member variables outside
273 # of their classes to avoid false positive
274 if {((!$isInClass && $isConst) || ($isInClass && $isStatic && $isConst)) && ![regexp $constVarRegex $lastIdentifier]} {
275 report $fileName $line "The constant names should match the following regex: $constVarRegex (found: $lastIdentifier)"
276 } elseif {$isInClass && $isStatic && !$isConst && ![regexp $staticMemberVariableRegex $lastIdentifier]} {
277 report $fileName $line "The static member variable names should match the following regex: $staticMemberVariableRegex (found: $lastIdentifier)"
278 } elseif {$isInClass && !$isStatic} {
279 if {$classOrStruct == "class" && ![regexp $classMemberVariableRegex $lastIdentifier]} {
280 report $fileName $line "The class member variable names should match the following regex: $classMemberVariableRegex (found: $lastIdentifier)"
281 } elseif {$classOrStruct == "struct" && ![regexp $structMemberVariableRegex $lastIdentifier] && ![regexp $classMemberVariableRegex $lastIdentifier]} {
282 report $fileName $line "The struct member variable names should match the following regex: $structMemberVariableRegex or the class member regex: $classMemberVariableRegex (found: $lastIdentifier)"
283 }
284 }
285 } elseif {$type == "leftbrace"} {
286 set state "consumeBraces"
287 incr bracesCounter
288 } elseif {$type == "leftparen"} {
289 set state "consumeParen"
290 incr parenCounter
291 } elseif {$type == "rightbrace"} {
292 # End of the state machine
293 set keepMachine 0
294 }
295
296 if {$type == "leftbracket"} {
297 incr bracketCounter
298 set state "consumeBracket"
299 }
300
301 # Reinit static, const and isVar
302 if {$type == "assign" || $type == "semicolon" || $type == "leftbrace"} {
303 set isStatic 0
304 set isConst 0
305 set isVar 1
306 }
307
308 if {$type == "semicolon"} {
309 set isTypedef 0
310 }
311 } elseif {$state == "consumeBraces"} {
312 if {$type == "leftbrace"} {
313 incr bracesCounter
314 } elseif {$type == "rightbrace"} {
315 incr bracesCounter -1
316 if {$bracesCounter == 0} {
317 set state "root"
318 }
319 }
320 } elseif {$state == "consumeParen"} {
321 if {$type == "leftparen"} {
322 incr parenCounter
323 } elseif {$type == "rightparen"} {
324 incr parenCounter -1
325 if {$parenCounter == 0} {
326 set state "root"
327 }
328 }
329 } elseif {$state == "consumeBracket"} {
330 if {$type == "leftbracket"} {
331 incr bracketCounter
332 } elseif {$type == "rightbracket"} {
333 incr bracketCounter -1
334 if {$bracketCounter == 0} {
335 set state "root"
336 }
337 }
338 }
339 }
340 }
341
342 if {$keepMachine} {
343 lappend machinesToKeep $m
344 }
345 }
346 set machines $machinesToKeep
347
348 set prev2 $prev1
349 set prev1 $type
350 }
351 }
@@ -0,0 +1,329
1 #!/usr/bin/tclsh
2 # Declaration order inside classes
3
4 proc createMachine {visibility initState} {
5 set machine [dict create visibility $visibility state $initState waitingFor "typedef" previousState "" bracesCounter 0 isStatic 0]
6 return $machine
7 }
8
9 proc createVisibilityMachine {} {
10 set machine [dict create state "beforeLeftBrace" visibilityState "waitingForPublic" bracesCounter 0 visibility ""]
11 return $machine
12 }
13
14 set tokenFilter {
15 public
16 protected
17 private
18 colon
19 typedef
20 class
21 struct
22 enum
23 static
24 const
25 identifier
26 operator
27 assign
28 semicolon
29 leftbrace
30 rightbrace
31 leftparen
32 rightparen
33 }
34
35 set globalOrder "The global order is public members then public slots, protected members then protected slots and private members then private slots."
36
37 foreach fileName [getSourceFileNames] {
38 set machines [list]
39 set visibilityMachines [list]
40
41 set visibilityState "waitingForPublic"
42
43 set prev1 ""
44 set prev2 ""
45 set lastIdentifier ""
46 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
47 set type [lindex $token 3]
48 set line [lindex $token 1]
49
50 if {$type == "identifier"} {
51 set lastIdentifier [lindex $token 0]
52 }
53
54 if {$type == "class" || $type == "struct"} {
55 lappend visibilityMachines [createVisibilityMachine]
56 }
57
58 if {$type == "colon" && ($prev1 == "public" || $prev1 == "protected" || $prev1 == "private")} {
59 lappend machines [createMachine $prev1 "beforeVisibility"]
60 }
61
62 # Machines for the visibility order
63 set visibilityMachinesToKeep [list]
64 foreach m $visibilityMachines {
65 set keepMachine 1
66 dict with m {
67 if {$state == "beforeLeftBrace"} {
68 if {$type == "semicolon"} {
69 set keepMachine 0
70 } elseif {$type == "leftbrace"} {
71 set state "root"
72 }
73 } elseif {$state == "root"} {
74 if {$type == "public" || $type == "protected" || $type == "private"} {
75 set visibility $type
76 set state "waitingForColon"
77 } elseif {$type == "leftbrace"} {
78 incr bracesCounter
79 set state "consumeBraces"
80 } elseif {$type == "rightbrace"} {
81 set keepMachine 0
82 }
83 } elseif {$state == "waitingForColon"} {
84 if {$type == "colon"} {
85 if {$visibility == "public" && $prev1 != "identifier"} {
86 if {$visibilityState == "waitingForPublicSlots"
87 || $visibilityState == "waitingForProtected"
88 || $visibilityState == "waitingForProtectedSlots"
89 || $visibilityState == "waitingForPrivate"
90 || $visibilityState == "waitingForPrivateSlots"
91 || $visibilityState == "done"} {
92 report $fileName $line "There should be at most one public visibility and it should be at the start of the class. $globalOrder"
93 } else {
94 set visibilityState "waitingForPublicSlots"
95 }
96 } elseif {$visibility == "public" && $prev1 == "identifier" && $lastIdentifier == "slots"} {
97 if {$visibilityState == "waitingForProtected"
98 || $visibilityState == "waitingForProtectedSlots"
99 || $visibilityState == "waitingForPrivate"
100 || $visibilityState == "waitingForPrivateSlots"
101 || $visibilityState == "done"} {
102 report $fileName $line "There should be at most one public slots visibility and it should be between public and protected. $globalOrder"
103 } else {
104 set visibilityState "waitingForProtected"
105 }
106 } elseif {$visibility == "protected" && $prev1 != "identifier"} {
107 if {$visibilityState == "waitingForProtectedSlots"
108 || $visibilityState == "waitingForPrivate"
109 || $visibilityState == "waitingForPrivateSlots"
110 || $visibilityState == "done"} {
111 report $fileName $line "There should be at most one protected visibility and it should be between public slots and protected slots. $globalOrder"
112 } else {
113 set visibilityState "waitingForProtectedSlots"
114 }
115 } elseif {$visibility == "protected" && $prev1 == "identifier" && $lastIdentifier == "slots"} {
116 if {$visibilityState == "waitingForPrivate"
117 || $visibilityState == "waitingForPrivateSlots"
118 || $visibilityState == "done"} {
119 report $fileName $line "There should be at most one protected slots visibility and it should be between protected and private. $globalOrder"
120 } else {
121 set visibilityState "waitingForPrivate"
122 }
123 } elseif {$visibility == "private" && $prev1 != "identifier"} {
124 if {$visibilityState == "waitingForPrivateSlots"
125 || $visibilityState == "done"} {
126 report $fileName $line "There should be at most one private visibility and it should be between protected slots and private slots. $globalOrder"
127 } else {
128 set visibilityState "waitingForPrivateSlots"
129 }
130 } elseif {$visibility == "private" && $prev1 == "identifier" && $lastIdentifier == "slots"} {
131 if {$visibilityState == "done"} {
132 report $fileName $line "There should be at most one private visibility and it should be the last of the class. $globalOrder"
133 } else {
134 set visibilityState "done"
135 }
136 }
137
138 set state "root"
139 }
140 } elseif {$state == "consumeBraces"} {
141 if {$type == "leftbrace"} {
142 incr bracesCounter
143 } elseif {$type == "rightbrace"} {
144 incr bracesCounter -1
145 if {$bracesCounter == 0} {
146 set state "root"
147 }
148 }
149 }
150 }
151
152 if {$keepMachine} {
153 lappend visibilityMachinesToKeep $m
154 }
155 }
156 set visibilityMachines $visibilityMachinesToKeep
157
158 # Machines for the declaration order inside a visibility
159 set machinesToKeep [list]
160 foreach m $machines {
161 set keepMachine 1
162 dict with m {
163 if {$state == "beforeVisibility" && $type == $visibility} {
164 set state "root"
165 } elseif {$state == "root"} {
166 if {$type == "public" || $type == "protected" || $type == "private" || $type == "rightbrace"} {
167 # End of the state machine when we reach the next
168 # visibility block
169 set keepMachine 0
170 } else {
171 if {$type == "static"} {
172 set isStatic 1
173 }
174
175 if {$waitingFor == "typedef"} {
176 if {$type == "typedef"} {
177 set state "consumeUntilNextSemiColon"
178 } else {
179 set waitingFor "enum"
180 }
181 }
182
183 if {$waitingFor == "enum"} {
184 if {$type == "typedef"} {
185 set state "consumeUntilNextSemiColon"
186 report $fileName $line "The typedefs should be before the enums"
187 } elseif {$type == "enum"} {
188 set state "consumeUntilNextSemiColon"
189 } else {
190 set waitingFor "class/struct"
191 }
192 }
193
194 if {$waitingFor == "class/struct"} {
195 if {$type == "typedef" || $type == "enum"} {
196 set state "consumeUntilNextSemiColon"
197 report $fileName $line "The typedefs and enums should be before the classes/structs"
198 } elseif {$type == "class" || $type == "struct"} {
199 set state "consumeUntilNextSemiColon"
200 } else {
201 set waitingFor "staticFunc"
202 }
203 }
204
205 if {$waitingFor == "staticFunc"} {
206 if {$type == "typedef" || $type == "enum" || $type == "class" || $type == "struct"} {
207 set state "consumeUntilNextSemiColon"
208 report $fileName $line "The typedefs, enums, classes and structs should be before the static functions"
209 } elseif {$prev1 == "identifier"} {
210 if {$type == "leftparen"} {
211 if {$isStatic} {
212 set state "consumeFunction"
213 } else {
214 set waitingFor "method"
215 }
216 } elseif {$type == "assign" || $type == "semicolon"} {
217 set waitingFor "staticVar"
218 }
219 }
220 }
221
222 if {$waitingFor == "staticVar"} {
223 if {$type == "typedef" || $type == "enum" || $type == "class" || $type == "struct"} {
224 set state "consumeUntilNextSemiColon"
225 report $fileName $line "The typedefs, enums, classes and structs should be before the static variables"
226 } elseif {$prev1 == "identifier"} {
227 if {$type == "leftparen"} {
228 if {$isStatic} {
229 set state "consumeFunction"
230 report $fileName $line "The static functions should be before the static variables"
231 } else {
232 set waitingFor "method"
233 }
234 } elseif {$type == "assign" || $type == "semicolon"} {
235 if {!$isStatic} {
236 set waitingFor "method"
237 }
238 if {$type != "semicolon"} {
239 set state "consumeUntilNextSemiColon"
240 } else {
241 set isStatic 0
242 }
243 }
244 }
245 }
246
247 if {$waitingFor == "method"} {
248 if {$type == "typedef" || $type == "enum" || $type == "class" || $type == "struct"} {
249 set state "consumeUntilNextSemiColon"
250 report $fileName $line "The typedefs, enums, classes and structs should be before the methods"
251 } elseif {$prev2 == "identifier" && $prev1 == "operator" && $type == "assign"} {
252 # override of operator=()
253 set state "consumeFunction"
254 } elseif {$prev1 == "identifier"} {
255 if {$type == "leftparen"} {
256 if {$isStatic} {
257 report $fileName $line "The static functions should be before the methods"
258 }
259 set state "consumeFunction"
260 } elseif {$type == "assign" || $type == "semicolon"} {
261 if {$isStatic} {
262 report $fileName $line "The static variables should be before the methods"
263 } else {
264 set waitingFor "var"
265 }
266 }
267 }
268 }
269
270 if {$waitingFor == "var"} {
271 if {$type == "typedef" || $type == "enum" || $type == "class" || $type == "struct"} {
272 set state "consumeUntilNextSemiColon"
273 report $fileName $line "The typedefs, enums, classes and structs should be before the variables"
274 } elseif {$prev1 == "identifier"} {
275 if {$type == "leftparen"} {
276 if {$isStatic} {
277 report $fileName $line "The static functions should be before the variables"
278 } else {
279 report $fileName $line "The methods should be before the variables"
280 }
281 set state "consumeFunction"
282 } elseif {$type == "assign" || $type == "semicolon"} {
283 if {$isStatic} {
284 report $fileName $line "The static variables should be before the variables"
285 }
286 }
287 }
288 }
289 }
290 } elseif {$state == "consumeUntilNextSemiColon"} {
291 set isStatic 0
292 if {$type == "semicolon"} {
293 set state "root"
294 } elseif {$type == "leftbrace"} {
295 incr bracesCounter
296 set previousState $state
297 set state "consumeBraces"
298 }
299 } elseif {$state == "consumeFunction"} {
300 set isStatic 0
301 if {$type == "semicolon"} {
302 set state "root"
303 } elseif {$type == "leftbrace"} {
304 incr bracesCounter
305 set previousState "root"
306 set state "consumeBraces"
307 }
308 } elseif {$state == "consumeBraces"} {
309 if {$type == "leftbrace"} {
310 incr bracesCounter
311 } elseif {$type == "rightbrace"} {
312 incr bracesCounter -1
313 if {$bracesCounter == 0} {
314 set state $previousState
315 }
316 }
317 }
318 }
319
320 if {$keepMachine} {
321 lappend machinesToKeep $m
322 }
323 }
324 set machines $machinesToKeep
325
326 set prev2 $prev1
327 set prev1 $type
328 }
329 } No newline at end of file
@@ -0,0 +1,166
1 #!/usr/bin/tclsh
2 # Forbid public member variables
3
4 set forbidPublicMemberVarInStruct [getParameter "also-forbid-public-member-var-in-struct" 0]
5
6 proc createMachine {type initState} {
7 set machine [dict create classOrStruct $type state $initState previousState "" bracesCounter 0 parenCounter 0 bracketCounter 0 isStatic 0 isTypedef 0 isRootClass 0]
8 return $machine
9 }
10
11 set tokenFilter {
12 public
13 protected
14 private
15 typedef
16 enum
17 class
18 struct
19 static
20 identifier
21 assign
22 semicolon
23 leftbrace
24 rightbrace
25 leftparen
26 rightparen
27 leftbracket
28 rightbracket
29 operator
30 }
31
32 foreach fileName [getSourceFileNames] {
33 if {[regexp {\.h$} $fileName]} {
34 set machines [list]
35
36 set rootClass 1
37 set lastIdentifier ""
38 set prev1 ""
39 foreach token [getTokens $fileName 1 0 -1 -1 $tokenFilter] {
40 set type [lindex $token 3]
41 set line [lindex $token 1]
42
43 if {$type == "identifier"} {
44 set lastIdentifier [lindex $token 0]
45 }
46
47 if {$rootClass && ($type == "class" || $type == "struct")} {
48 set m [createMachine $type "beforeLeftBrace"]
49 dict set m isRootClass 1
50 lappend machines $m
51 set rootClass 0
52 }
53
54 set machinesToKeep [list]
55 foreach m $machines {
56 set keepMachine 1
57 dict with m {
58 if {$state == "beforeLeftBrace"} {
59 if {$type == "leftbrace"} {
60 if {$classOrStruct == "class"} {
61 set state "root"
62 } elseif {$classOrStruct == "struct"} {
63 set state "public"
64 }
65 } elseif {$type == "semicolon"} {
66 set keepMachine 0
67 set rootClass $isRootClass
68 }
69 } elseif {$state == "root"} {
70 if {$type == "public"} {
71 set state "public"
72 } elseif {$type == "leftbrace"} {
73 incr bracesCounter
74 set previousState $state
75 set state "consumeBraces"
76 } elseif {$type == "rightbrace"} {
77 set keepMachine 0
78 set rootClass $isRootClass
79 }
80 } elseif {$state == "public"} {
81 if {$type == "class" || $type == "struct"} {
82 lappend machinesToKeep [createMachine $type "beforeLeftBrace"]
83 }
84
85 if {$type == "static"} {
86 set isStatic 1
87 }
88 if {$type == "typedef"} {
89 set isTypedef 1
90 }
91
92 if {$prev1 == "identifier" && ($type == "assign" || $type == "semicolon" || $type == "leftbracket")} {
93 if {!$isStatic && !$isTypedef} {
94 if {($classOrStruct == "class") || ($classOrStruct == "struct" && $forbidPublicMemberVarInStruct)} {
95 report $fileName $line "Public member variables are forbidden in $classOrStruct (found: $lastIdentifier)"
96 }
97 }
98 } elseif {$type == "protected" || $type == "private"} {
99 set isStatic 0
100 set isTypedef 0
101 set state "root"
102 } elseif {$type == "leftbrace"} {
103 incr bracesCounter
104 set previousState $state
105 set state "consumeBraces"
106 } elseif {$type == "leftparen"} {
107 incr parenCounter
108 set previousState $state
109 set state "consumeParen"
110 } elseif {$type == "rightbrace"} {
111 set keepMachine 0
112 set rootClass $isRootClass
113 }
114
115 if {$type == "leftbracket"} {
116 incr bracketCounter
117 set previousState $state
118 set state "consumeBracket"
119 }
120
121 if {$type == "semicolon" || $type == "leftbrace"} {
122 set isStatic 0
123 }
124 if {$type == "semicolon"} {
125 set isTypedef 0
126 }
127 } elseif {$state == "consumeBraces"} {
128 if {$type == "leftbrace"} {
129 incr bracesCounter
130 } elseif {$type == "rightbrace"} {
131 incr bracesCounter -1
132 if {$bracesCounter == 0} {
133 set state $previousState
134 }
135 }
136 } elseif {$state == "consumeParen"} {
137 if {$type == "leftparen"} {
138 incr parenCounter
139 } elseif {$type == "rightparen"} {
140 incr parenCounter -1
141 if {$parenCounter == 0} {
142 set state $previousState
143 }
144 }
145 } elseif {$state == "consumeBracket"} {
146 if {$type == "leftbracket"} {
147 incr bracketCounter
148 } elseif {$type == "rightbracket"} {
149 incr bracketCounter -1
150 if {$bracketCounter == 0} {
151 set state $previousState
152 }
153 }
154 }
155 }
156
157 if {$keepMachine} {
158 lappend machinesToKeep $m
159 }
160 }
161 set machines $machinesToKeep
162
163 set prev1 $type
164 }
165 }
166 }
@@ -0,0 +1,60
1 #!/usr/bin/tclsh
2 # Prefer C++ includes of the C std headers (cstdio instead of stdio.h for instance)
3
4 set cStdHeaders {
5 assert.h
6 complex.h
7 ctype.h
8 errno.h
9 fenv.h
10 float.h
11 inttypes.h
12 iso646.h
13 limits.h
14 locale.h
15 math.h
16 setjmp.h
17 signal.h
18 stdalign.h
19 stdarg.h
20 stdbool.h
21 stddef.h
22 stdint.h
23 stdio.h
24 stdlib.h
25 string.h
26 tgmath.h
27 time.h
28 uchar.h
29 wchar.h
30 wctype.h
31 }
32
33 set cStdHeadersWithDifferentCppEquivalent [dict create \
34 stdatomic.h atomic \
35 threads.h thread \
36 ]
37
38 set cStdHeadersWithNoCppEquivalent {
39 stdnoreturn.h
40 }
41
42 foreach fileName [getSourceFileNames] {
43 foreach token [getTokens $fileName 1 0 -1 -1 {pp_hheader}] {
44 set line [lindex $token 1]
45 set value [lindex $token 0]
46
47 if {[regexp {^[^<]*?<(.*)>[^>]*?$} $value matched headerName]} {
48 if {[lsearch $cStdHeaders $headerName] != -1} {
49 set headerWithoutExt [string range $headerName 0 [expr [string length $headerName] - 3]]
50 set cppHeader "c$headerWithoutExt"
51 report $fileName $line "$headerName is a C include, use the equivalent C++ include <$cppHeader>"
52 } elseif {[dict exists $cStdHeadersWithDifferentCppEquivalent $headerName]} {
53 set cppHeader [dict get $cStdHeadersWithDifferentCppEquivalent $headerName]
54 report $fileName $line "$headerName is a C include, use the equivalent C++ include <$cppHeader>"
55 } elseif {[lsearch $cStdHeadersWithNoCppEquivalent $headerName] != -1} {
56 report $fileName $line "$headerName is a C include without C++ equivalent. Use the C++ constructions instead of relying on C headers."
57 }
58 }
59 }
60 }
General Comments 0
You need to be logged in to leave comments. Login now