1 # vim: set ts=8 sts=4 et sw=4 tw=99:
2 # This Source Code Form is subject to the terms of the Mozilla Public
3 # License, v. 2.0. If a copy of the MPL was not distributed with this
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 # ----------------------------------------------------------------------------
7 # This script checks various aspects of SpiderMonkey code style. The current checks are as
10 # We check the following things in headers.
12 # - No cyclic dependencies.
14 # - No normal header should #include a inlines.h/-inl.h file.
16 # - #ifndef wrappers should have the right form. (XXX: not yet implemented)
17 # - Every header file should have one.
18 # - The guard name used should be appropriate for the filename.
20 # We check the following things in all files.
22 # - #includes should have full paths, e.g. "jit/Ion.h", not "Ion.h".
24 # - #includes should use the appropriate form for system headers (<...>) and
25 # local headers ("...").
27 # - #includes should be ordered correctly.
28 # - Each one should be in the correct section.
29 # - Alphabetical order should be used within sections.
30 # - Sections should be in the right order.
31 # Note that the presence of #if/#endif blocks complicates things, to the
32 # point that it's not always clear where a conditionally-compiled #include
33 # statement should go, even to a human. Therefore, we check the #include
34 # statements within each #if/#endif block (including nested ones) in
35 # isolation, but don't try to do any order checking between such blocks.
36 # ----------------------------------------------------------------------------
38 from __future__
import print_function
45 # We don't bother checking files in these directories, because they're (a) auxiliary or (b)
46 # imported code that doesn't follow our coding style.
47 ignored_js_src_dirs
= [
48 'js/src/config/', # auxiliary stuff
49 'js/src/ctypes/libffi/', # imported code
50 'js/src/devtools/', # auxiliary stuff
51 'js/src/editline/', # imported code
52 'js/src/gdb/', # auxiliary stuff
53 'js/src/vtune/' # imported code
56 # We ignore #includes of these files, because they don't follow the usual rules.
57 included_inclnames_to_ignore
= set([
58 'ffi.h', # generated in ctypes/libffi/
59 'devtools/sharkctl.h', # we ignore devtools/ in general
60 'devtools/Instruments.h', # we ignore devtools/ in general
61 'double-conversion/double-conversion.h', # strange MFBT case
62 'javascript-trace.h', # generated in $OBJDIR if HAVE_DTRACE is defined
63 'frontend/ReservedWordsGenerated.h', # generated in $OBJDIR
64 'gc/StatsPhasesGenerated.h', # generated in $OBJDIR
65 'gc/StatsPhasesGenerated.cpp', # generated in $OBJDIR
66 'jit/LOpcodes.h', # generated in $OBJDIR
67 'jit/MOpcodes.h', # generated in $OBJDIR
68 'jscustomallocator.h', # provided by embedders; allowed to be missing
69 'js-config.h', # generated in $OBJDIR
71 'FuzzerDefs.h', # included without a path
72 'FuzzingInterface.h', # included without a path
73 'mozmemory.h', # included without a path
79 'private/pprio.h', # NSPR
85 'selfhosted.out.h', # generated in $OBJDIR
86 'shellmoduleloader.out.h', # generated in $OBJDIR
87 'unicode/timezone.h', # ICU
88 'unicode/plurrule.h', # ICU
89 'unicode/ucal.h', # ICU
90 'unicode/uchar.h', # ICU
91 'unicode/uclean.h', # ICU
92 'unicode/ucol.h', # ICU
93 'unicode/udat.h', # ICU
94 'unicode/udatpg.h', # ICU
95 'unicode/udisplaycontext.h', # ICU
96 'unicode/uenum.h', # ICU
97 'unicode/uloc.h', # ICU
98 'unicode/unistr.h', # ICU
99 'unicode/unorm2.h', # ICU
100 'unicode/unum.h', # ICU
101 'unicode/unumsys.h', # ICU
102 'unicode/upluralrules.h', # ICU
103 'unicode/ureldatefmt.h', # ICU
104 'unicode/ustring.h', # ICU
105 'unicode/utypes.h', # ICU
106 'vtune/VTuneWrapper.h' # VTune
109 # These files have additional constraints on where they are #included, so we
110 # ignore #includes of them when checking #include ordering.
111 oddly_ordered_inclnames
= set([
112 'ctypes/typedefs.h', # Included multiple times in the body of ctypes/CTypes.h
113 'frontend/BinSource-auto.h', # Included in the body of frontend/BinSource.h
114 # Included in the body of frontend/TokenStream.h
115 'frontend/ReservedWordsGenerated.h',
116 'gc/StatsPhasesGenerated.h', # Included in the body of gc/Statistics.h
117 'gc/StatsPhasesGenerated.cpp', # Included in the body of gc/Statistics.cpp
118 'psapi.h', # Must be included after "util/Windows.h" on Windows
119 'machine/endian.h', # Must be included after <sys/types.h> on BSD
120 'winbase.h', # Must precede other system headers(?)
121 'windef.h' # Must precede other system headers(?)
124 # The files in tests/style/ contain code that fails this checking in various
125 # ways. Here is the output we expect. If the actual output differs from
126 # this, one of the following must have happened.
127 # - New SpiderMonkey code violates one of the checked rules.
128 # - The tests/style/ files have changed without expected_output being changed
130 # - This script has been broken somehow.
132 expected_output
= '''\
133 js/src/tests/style/BadIncludes2.h:1: error:
134 vanilla header includes an inline-header file "tests/style/BadIncludes2-inl.h"
136 js/src/tests/style/BadIncludes.h:3: error:
137 the file includes itself
139 js/src/tests/style/BadIncludes.h:6: error:
140 "BadIncludes2.h" is included using the wrong path;
141 did you forget a prefix, or is the file not yet committed?
143 js/src/tests/style/BadIncludes.h:8: error:
144 <tests/style/BadIncludes2.h> should be included using
145 the #include "..." form
147 js/src/tests/style/BadIncludes.h:10: error:
148 "stdio.h" is included using the wrong path;
149 did you forget a prefix, or is the file not yet committed?
151 js/src/tests/style/BadIncludesOrder-inl.h:5:6: error:
152 "vm/JSScript-inl.h" should be included after "vm/Interpreter-inl.h"
154 js/src/tests/style/BadIncludesOrder-inl.h:6:7: error:
155 "vm/Interpreter-inl.h" should be included after "js/Value.h"
157 js/src/tests/style/BadIncludesOrder-inl.h:7:8: error:
158 "js/Value.h" should be included after "ds/LifoAlloc.h"
160 js/src/tests/style/BadIncludesOrder-inl.h:8:9: error:
161 "ds/LifoAlloc.h" should be included after "jsapi.h"
163 js/src/tests/style/BadIncludesOrder-inl.h:9:10: error:
164 "jsapi.h" should be included after <stdio.h>
166 js/src/tests/style/BadIncludesOrder-inl.h:10:11: error:
167 <stdio.h> should be included after "mozilla/HashFunctions.h"
169 js/src/tests/style/BadIncludesOrder-inl.h:28:29: error:
170 "vm/JSScript.h" should be included after "vm/JSFunction.h"
172 (multiple files): error:
173 header files form one or more cycles
175 tests/style/HeaderCycleA1.h
176 -> tests/style/HeaderCycleA2.h
177 -> tests/style/HeaderCycleA3.h
178 -> tests/style/HeaderCycleA1.h
180 tests/style/HeaderCycleB1-inl.h
181 -> tests/style/HeaderCycleB2-inl.h
182 -> tests/style/HeaderCycleB3-inl.h
183 -> tests/style/HeaderCycleB4-inl.h
184 -> tests/style/HeaderCycleB1-inl.h
185 -> tests/style/jsheadercycleB5inlines.h
186 -> tests/style/HeaderCycleB1-inl.h
187 -> tests/style/HeaderCycleB4-inl.h
196 actual_output
.append(line
+ '\n')
199 def error(filename
, linenum
, *lines
):
201 if linenum
is not None:
202 location
+= ':' + str(linenum
)
203 out(location
+ ': error:')
209 class FileKind(object):
219 if filename
.endswith('.c'):
222 if filename
.endswith('.cpp'):
225 if filename
.endswith(('inlines.h', '-inl.h')):
226 return FileKind
.INL_H
228 if filename
.endswith('.h'):
231 if filename
.endswith('.tbl'):
234 if filename
.endswith('.msg'):
237 error(filename
, None, 'unknown file kind')
240 def check_style(enable_fixup
):
241 # We deal with two kinds of name.
242 # - A "filename" is a full path to a file from the repository root.
243 # - An "inclname" is how a file is referred to in a #include statement.
245 # Examples (filename -> inclname)
246 # - "mfbt/Attributes.h" -> "mozilla/Attributes.h"
247 # - "mfbt/decimal/Decimal.h -> "mozilla/Decimal.h"
248 # - "mozglue/misc/TimeStamp.h -> "mozilla/TimeStamp.h"
249 # - "memory/mozalloc/mozalloc.h -> "mozilla/mozalloc.h"
250 # - "js/public/Vector.h" -> "js/Vector.h"
251 # - "js/src/vm/String.h" -> "vm/String.h"
253 non_js_dirnames
= ('mfbt/',
255 'mozglue/') # type: tuple(str)
256 non_js_inclnames
= set() # type: set(inclname)
257 js_names
= dict() # type: dict(filename, inclname)
259 # Process files in js/src.
260 js_src_root
= os
.path
.join('js', 'src')
261 for dirpath
, dirnames
, filenames
in os
.walk(js_src_root
):
262 if dirpath
== js_src_root
:
263 # Skip any subdirectories that contain a config.status file
266 for dirname
in dirnames
:
267 path
= os
.path
.join(dirpath
, dirname
, 'config.status')
268 if os
.path
.isfile(path
):
269 builddirs
.append(dirname
)
270 for dirname
in builddirs
:
271 dirnames
.remove(dirname
)
272 for filename
in filenames
:
273 filepath
= os
.path
.join(dirpath
, filename
).replace('\\', '/')
274 if not filepath
.startswith(tuple(ignored_js_src_dirs
)) and \
275 filepath
.endswith(('.c', '.cpp', '.h', '.tbl', '.msg')):
276 inclname
= filepath
[len('js/src/'):]
277 js_names
[filepath
] = inclname
279 # Look for header files in directories in non_js_dirnames.
280 for non_js_dir
in non_js_dirnames
:
281 for dirpath
, dirnames
, filenames
in os
.walk(non_js_dir
):
282 for filename
in filenames
:
283 if filename
.endswith('.h'):
284 inclname
= 'mozilla/' + filename
285 non_js_inclnames
.add(inclname
)
287 # Look for header files in js/public.
288 js_public_root
= os
.path
.join('js', 'public')
289 for dirpath
, dirnames
, filenames
in os
.walk(js_public_root
):
290 for filename
in filenames
:
291 if filename
.endswith('.h'):
292 filepath
= os
.path
.join(dirpath
, filename
).replace('\\', '/')
293 inclname
= 'js/' + filepath
[len('js/public/'):]
294 js_names
[filepath
] = inclname
296 all_inclnames
= non_js_inclnames |
set(js_names
.values())
298 edges
= dict() # type: dict(inclname, set(inclname))
300 # We don't care what's inside the MFBT and MOZALLOC files, but because they
301 # are #included from JS files we have to add them to the inclusion graph.
302 for inclname
in non_js_inclnames
:
303 edges
[inclname
] = set()
305 # Process all the JS files.
306 for filename
in js_names
.keys():
307 inclname
= js_names
[filename
]
308 file_kind
= FileKind
.get(filename
)
309 if file_kind
== FileKind
.C
or file_kind
== FileKind
.CPP
or \
310 file_kind
== FileKind
.H
or file_kind
== FileKind
.INL_H
:
311 included_h_inclnames
= set() # type: set(inclname)
313 with
open(filename
) as f
:
317 code
= code
.sorted(inclname
)
318 with
open(filename
, 'w') as f
:
319 f
.write(code
.to_source())
321 check_file(filename
, inclname
, file_kind
, code
,
322 all_inclnames
, included_h_inclnames
)
324 edges
[inclname
] = included_h_inclnames
326 find_cycles(all_inclnames
, edges
)
328 # Compare expected and actual output.
329 difflines
= difflib
.unified_diff(expected_output
, actual_output
,
330 fromfile
='check_spidermonkey_style.py expected output',
331 tofile
='check_spidermonkey_style.py actual output')
333 for diffline
in difflines
:
335 print(diffline
, end
='')
340 def module_name(name
):
341 '''Strip the trailing .cpp, .h, inlines.h or -inl.h from a filename.'''
343 return name
.replace('inlines.h', '').replace('-inl.h', '').replace('.h', '').replace('.cpp', '') # NOQA: E501
346 def is_module_header(enclosing_inclname
, header_inclname
):
347 '''Determine if an included name is the "module header", i.e. should be
348 first in the file.'''
350 module
= module_name(enclosing_inclname
)
352 # Normal case, e.g. module == "foo/Bar", header_inclname == "foo/Bar.h".
353 if module
== module_name(header_inclname
):
356 # A public header, e.g. module == "foo/Bar", header_inclname == "js/Bar.h".
357 m
= re
.match(r
'js\/(.*)\.h', header_inclname
)
358 if m
is not None and module
.endswith('/' + m
.group(1)):
364 class Include(object):
365 '''Important information for a single #include statement.'''
367 def __init__(self
, include_prefix
, inclname
, line_suffix
, linenum
, is_system
):
368 self
.include_prefix
= include_prefix
369 self
.line_suffix
= line_suffix
370 self
.inclname
= inclname
371 self
.linenum
= linenum
372 self
.is_system
= is_system
374 def is_style_relevant(self
):
375 # Includes are style-relevant; that is, they're checked by the pairwise
376 # style-checking algorithm in check_file.
379 def section(self
, enclosing_inclname
):
380 '''Identify which section inclname belongs to.
382 The section numbers are as follows.
383 0. Module header (e.g. jsfoo.h or jsfooinlines.h within jsfoo.cpp)
386 3. jsfoo.h, prmjtime.h, etc
390 7. non-.h, e.g. *.tbl, *.msg
396 if not self
.inclname
.endswith('.h'):
399 # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
401 if is_module_header(enclosing_inclname
, self
.inclname
):
404 if '/' in self
.inclname
:
405 if self
.inclname
.startswith('mozilla/'):
408 if self
.inclname
.endswith('-inl.h'):
413 if self
.inclname
.endswith('inlines.h'):
420 return '<' + self
.inclname
+ '>'
422 return '"' + self
.inclname
+ '"'
424 def sort_key(self
, enclosing_inclname
):
425 return (self
.section(enclosing_inclname
), self
.inclname
.lower())
428 return self
.include_prefix
+ self
.quote() + self
.line_suffix
+ '\n'
431 class CppBlock(object):
432 '''C preprocessor block: a whole file or a single #if/#elif/#else block.
434 A #if/#endif block is the contents of a #if/#endif (or similar) section.
435 The top-level block, which is not within a #if/#endif pair, is also
438 Each kid is either an Include (representing a #include), OrdinaryCode, or
439 a nested CppBlock.'''
441 def __init__(self
, start_line
=""):
442 self
.start
= start_line
446 def is_style_relevant(self
):
449 def append_ordinary_line(self
, line
):
450 if len(self
.kids
) == 0 or not isinstance(self
.kids
[-1], OrdinaryCode
):
451 self
.kids
.append(OrdinaryCode())
452 self
.kids
[-1].lines
.append(line
)
454 def style_relevant_kids(self
):
455 """ Return a list of kids in this block that are style-relevant. """
456 return [kid
for kid
in self
.kids
if kid
.is_style_relevant()]
458 def sorted(self
, enclosing_inclname
):
459 """Return a hopefully-sorted copy of this block. Implements --fixup.
461 When in doubt, this leaves the code unchanged.
464 def pretty_sorted_includes(includes
):
465 """ Return a new list containing the given includes, in order,
466 with blank lines separating sections. """
467 keys
= [inc
.sort_key(enclosing_inclname
) for inc
in includes
]
468 if sorted(keys
) == keys
:
469 return includes
# if nothing is out of order, don't touch anything
472 current_section
= None
473 for (section
, _
), inc
in sorted(zip(keys
, includes
)):
474 if current_section
is not None and section
!= current_section
:
475 output
.append(OrdinaryCode(["\n"])) # blank line
477 current_section
= section
480 def should_try_to_sort(includes
):
481 if 'tests/style/BadIncludes' in enclosing_inclname
:
482 return False # don't straighten the counterexample
483 if any(inc
.inclname
in oddly_ordered_inclnames
for inc
in includes
):
484 return False # don't sort batches containing odd includes
485 if includes
== sorted(includes
, key
=lambda inc
: inc
.sort_key(enclosing_inclname
)):
486 return False # it's already sorted, avoid whitespace-only fixups
489 # The content of the eventual output of this method.
492 # The current batch of includes to sort. This list only ever contains Include objects
493 # and whitespace OrdinaryCode objects.
497 """Sort the contents of `batch` and move it to `output`."""
499 assert all(isinstance(item
, Include
)
500 or (isinstance(item
, OrdinaryCode
) and "".join(item
.lines
).isspace())
503 # Here we throw away the blank lines.
504 # `pretty_sorted_includes` puts them back.
506 last_include_index
= -1
507 for i
, item
in enumerate(batch
):
508 if isinstance(item
, Include
):
509 includes
.append(item
)
510 last_include_index
= i
511 cutoff
= last_include_index
+ 1
513 if should_try_to_sort(includes
):
514 output
.extend(pretty_sorted_includes(
515 includes
) + batch
[cutoff
:])
520 for kid
in self
.kids
:
521 if isinstance(kid
, CppBlock
):
523 output
.append(kid
.sorted(enclosing_inclname
))
524 elif isinstance(kid
, Include
):
527 assert isinstance(kid
, OrdinaryCode
)
528 if kid
.to_source().isspace():
536 result
.start
= self
.start
537 result
.end
= self
.end
542 return self
.start
+ ''.join(kid
.to_source() for kid
in self
.kids
) + self
.end
545 class OrdinaryCode(object):
546 ''' A list of lines of code that aren't #include/#if/#else/#endif lines. '''
548 def __init__(self
, lines
=None):
549 self
.lines
= lines
if lines
is not None else []
551 def is_style_relevant(self
):
555 return ''.join(self
.lines
)
558 # A "snippet" is one of:
560 # * Include - representing an #include line
561 # * CppBlock - a whole file or #if/#elif/#else block; contains a list of snippets
562 # * OrdinaryCode - representing lines of non-#include-relevant code
565 block_stack
= [CppBlock()]
567 # Extract the #include statements as a tree of snippets.
568 for linenum
, line
in enumerate(f
, start
=1):
569 if line
.lstrip().startswith('#'):
570 # Look for a |#include "..."| line.
571 m
= re
.match(r
'(\s*#\s*include\s+)"([^"]*)"(.*)', line
)
573 prefix
, inclname
, suffix
= m
.groups()
574 block_stack
[-1].kids
.append(Include(prefix
,
575 inclname
, suffix
, linenum
, is_system
=False))
578 # Look for a |#include <...>| line.
579 m
= re
.match(r
'(\s*#\s*include\s+)<([^>]*)>(.*)', line
)
581 prefix
, inclname
, suffix
= m
.groups()
582 block_stack
[-1].kids
.append(Include(prefix
,
583 inclname
, suffix
, linenum
, is_system
=True))
586 # Look for a |#{if,ifdef,ifndef}| line.
587 m
= re
.match(r
'\s*#\s*(if|ifdef|ifndef)\b', line
)
590 new_block
= CppBlock(line
)
591 block_stack
[-1].kids
.append(new_block
)
592 block_stack
.append(new_block
)
595 # Look for a |#{elif,else}| line.
596 m
= re
.match(r
'\s*#\s*(elif|else)\b', line
)
598 # Close the current block, and open an adjacent one.
600 new_block
= CppBlock(line
)
601 block_stack
[-1].kids
.append(new_block
)
602 block_stack
.append(new_block
)
605 # Look for a |#endif| line.
606 m
= re
.match(r
'\s*#\s*endif\b', line
)
608 # Close the current block.
609 block_stack
.pop().end
= line
610 if len(block_stack
) == 0:
612 "#endif without #if at line " + str(linenum
))
615 # Otherwise, we have an ordinary line.
616 block_stack
[-1].append_ordinary_line(line
)
618 if len(block_stack
) > 1:
619 raise ValueError("unmatched #if")
620 return block_stack
[-1]
623 def check_file(filename
, inclname
, file_kind
, code
, all_inclnames
, included_h_inclnames
):
625 def check_include_statement(include
):
626 '''Check the style of a single #include statement.'''
628 if include
.is_system
:
629 # Check it is not a known local file (in which case it's probably a system header).
630 if include
.inclname
in included_inclnames_to_ignore
or \
631 include
.inclname
in all_inclnames
:
632 error(filename
, include
.linenum
,
633 include
.quote() + ' should be included using',
634 'the #include "..." form')
637 if include
.inclname
not in included_inclnames_to_ignore
:
638 included_kind
= FileKind
.get(include
.inclname
)
640 # Check the #include path has the correct form.
641 if include
.inclname
not in all_inclnames
:
642 error(filename
, include
.linenum
,
643 include
.quote() + ' is included using the wrong path;',
644 'did you forget a prefix, or is the file not yet committed?')
646 # Record inclusions of .h files for cycle detection later.
647 # (Exclude .tbl and .msg files.)
648 elif included_kind
== FileKind
.H
or included_kind
== FileKind
.INL_H
:
649 included_h_inclnames
.add(include
.inclname
)
651 # Check a H file doesn't #include an INL_H file.
652 if file_kind
== FileKind
.H
and included_kind
== FileKind
.INL_H
:
653 error(filename
, include
.linenum
,
654 'vanilla header includes an inline-header file ' + include
.quote())
656 # Check a file doesn't #include itself. (We do this here because the cycle
657 # detection below doesn't detect this case.)
658 if inclname
== include
.inclname
:
659 error(filename
, include
.linenum
,
660 'the file includes itself')
662 def check_includes_order(include1
, include2
):
663 '''Check the ordering of two #include statements.'''
665 if include1
.inclname
in oddly_ordered_inclnames
or \
666 include2
.inclname
in oddly_ordered_inclnames
:
669 section1
= include1
.section(inclname
)
670 section2
= include2
.section(inclname
)
671 if (section1
> section2
) or \
672 ((section1
== section2
) and (include1
.inclname
.lower() > include2
.inclname
.lower())):
673 error(filename
, str(include1
.linenum
) + ':' + str(include2
.linenum
),
674 include1
.quote() + ' should be included after ' + include2
.quote())
676 # Check the extracted #include statements, both individually, and the ordering of
677 # adjacent pairs that live in the same block.
678 def pair_traverse(prev
, this
):
679 if isinstance(this
, Include
):
680 check_include_statement(this
)
681 if isinstance(prev
, Include
):
682 check_includes_order(prev
, this
)
684 kids
= this
.style_relevant_kids()
685 for prev2
, this2
in zip([None] + kids
[0:-1], kids
):
686 pair_traverse(prev2
, this2
)
688 pair_traverse(None, code
)
691 def find_cycles(all_inclnames
, edges
):
692 '''Find and draw any cycles.'''
694 SCCs
= tarjan(all_inclnames
, edges
)
696 # The various sorted() calls below ensure the output is deterministic.
703 out(' ' * indent
+ ('-> ' if indent
else ' ') + v
)
707 for succ
in sorted(edges
[v
]):
709 draw(succ
, indent
+ 1)
710 draw(sorted(c
)[0], 0)
713 have_drawn_an_SCC
= False
714 for scc
in sorted(SCCs
):
716 if not have_drawn_an_SCC
:
717 error('(multiple files)', None,
718 'header files form one or more cycles')
719 have_drawn_an_SCC
= True
724 # Tarjan's algorithm for finding the strongly connected components (SCCs) of a graph.
725 # https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
733 def strongconnect(v
, index
):
734 # Set the depth index for v to the smallest unused index
735 vertex_index
[v
] = index
736 vertex_lowlink
[v
] = index
740 # Consider successors of v
742 if w
not in vertex_index
:
743 # Successor w has not yet been visited; recurse on it
744 index
= strongconnect(w
, index
)
745 vertex_lowlink
[v
] = min(vertex_lowlink
[v
], vertex_lowlink
[w
])
747 # Successor w is in stack S and hence in the current SCC
748 vertex_lowlink
[v
] = min(vertex_lowlink
[v
], vertex_index
[w
])
750 # If v is a root node, pop the stack and generate an SCC
751 if vertex_lowlink
[v
] == vertex_index
[v
]:
760 if v
not in vertex_index
:
761 index
= strongconnect(v
, index
)
767 if sys
.argv
[1:] == ["--fixup"]:
768 # Sort #include directives in-place. Fixup mode doesn't solve
769 # all possible silliness that the script checks for; it's just a
770 # hack for the common case where renaming a header causes style
773 elif sys
.argv
[1:] == []:
776 print("TEST-UNEXPECTED-FAIL | check_spidermonkey_style.py | unexpected command "
777 "line options: " + repr(sys
.argv
[1:]))
780 ok
= check_style(fixup
)
783 print('TEST-PASS | check_spidermonkey_style.py | ok')
785 print('TEST-UNEXPECTED-FAIL | check_spidermonkey_style.py | ' +
786 'actual output does not match expected output; diff is above.')
787 print('TEST-UNEXPECTED-FAIL | check_spidermonkey_style.py | ' +
788 'Hint: If the problem is that you renamed a header, and many #includes ' +
789 'are no longer in alphabetical order, commit your work and then try ' +
790 '`check_spidermonkey_style.py --fixup`. ' +
791 'You need to commit first because --fixup modifies your files in place.')
793 sys
.exit(0 if ok
else 1)
796 if __name__
== '__main__':