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 absolute_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
54 "js/src/zydis/", # imported code
57 # We ignore #includes of these files, because they don't follow the usual rules.
58 included_inclnames_to_ignore
= set(
60 "ffi.h", # generated in ctypes/libffi/
61 "devtools/Instruments.h", # we ignore devtools/ in general
62 "double-conversion/double-conversion.h", # strange MFBT case
63 "javascript-trace.h", # generated in $OBJDIR if HAVE_DTRACE is defined
64 "frontend/ReservedWordsGenerated.h", # generated in $OBJDIR
65 "frontend/smoosh_generated.h", # generated in $OBJDIR
66 "gc/StatsPhasesGenerated.h", # generated in $OBJDIR
67 "gc/StatsPhasesGenerated.inc", # generated in $OBJDIR
68 "jit/CacheIROpsGenerated.h", # generated in $OBJDIR
69 "jit/LOpcodesGenerated.h", # generated in $OBJDIR
70 "jit/MOpcodesGenerated.h", # generated in $OBJDIR
71 "js/ProfilingCategoryList.h", # comes from mozglue/baseprofiler
72 "jscustomallocator.h", # provided by embedders; allowed to be missing
73 "js-config.h", # generated in $OBJDIR
75 "FuzzerDefs.h", # included without a path
76 "FuzzingInterface.h", # included without a path
77 "mozmemory.h", # included without a path
83 "private/pprio.h", # NSPR
89 "selfhosted.out.h", # generated in $OBJDIR
90 "shellmoduleloader.out.h", # generated in $OBJDIR
91 "unicode/basictz.h", # ICU
92 "unicode/locid.h", # ICU
93 "unicode/plurrule.h", # ICU
94 "unicode/putil.h", # ICU
95 "unicode/timezone.h", # ICU
96 "unicode/ucal.h", # ICU
97 "unicode/uchar.h", # ICU
98 "unicode/uclean.h", # ICU
99 "unicode/ucol.h", # ICU
100 "unicode/ucurr.h", # ICU
101 "unicode/udat.h", # ICU
102 "unicode/udata.h", # ICU
103 "unicode/udateintervalformat.h", # ICU
104 "unicode/udatpg.h", # ICU
105 "unicode/udisplaycontext.h", # ICU
106 "unicode/uenum.h", # ICU
107 "unicode/ufieldpositer.h", # ICU
108 "unicode/uformattedvalue.h", # ICU
109 "unicode/ulistformatter.h", # ICU
110 "unicode/uldnames.h", # ICU
111 "unicode/uloc.h", # ICU
112 "unicode/umachine.h", # ICU
113 "unicode/uniset.h", # ICU
114 "unicode/unistr.h", # ICU
115 "unicode/unorm2.h", # ICU
116 "unicode/unum.h", # ICU
117 "unicode/unumberformatter.h", # ICU
118 "unicode/unumsys.h", # ICU
119 "unicode/upluralrules.h", # ICU
120 "unicode/ureldatefmt.h", # ICU
121 "unicode/ures.h", # ICU
122 "unicode/ustring.h", # ICU
123 "unicode/utypes.h", # ICU
124 "unicode/uversion.h", # ICU
125 "vtune/VTuneWrapper.h", # VTune
126 "zydis/ZydisAPI.h", # Zydis
130 # These files have additional constraints on where they are #included, so we
131 # ignore #includes of them when checking #include ordering.
132 oddly_ordered_inclnames
= set(
134 "ctypes/typedefs.h", # Included multiple times in the body of ctypes/CTypes.h
135 # Included in the body of frontend/TokenStream.h
136 "frontend/ReservedWordsGenerated.h",
137 "gc/StatsPhasesGenerated.h", # Included in the body of gc/Statistics.h
138 "gc/StatsPhasesGenerated.inc", # Included in the body of gc/Statistics.cpp
139 "psapi.h", # Must be included after "util/Windows.h" on Windows
140 "machine/endian.h", # Must be included after <sys/types.h> on BSD
141 "winbase.h", # Must precede other system headers(?)
142 "windef.h", # Must precede other system headers(?)
146 # The files in tests/style/ contain code that fails this checking in various
147 # ways. Here is the output we expect. If the actual output differs from
148 # this, one of the following must have happened.
149 # - New SpiderMonkey code violates one of the checked rules.
150 # - The tests/style/ files have changed without expected_output being changed
152 # - This script has been broken somehow.
154 expected_output
= """\
155 js/src/tests/style/BadIncludes.h:3: error:
156 the file includes itself
158 js/src/tests/style/BadIncludes.h:6: error:
159 "BadIncludes2.h" is included using the wrong path;
160 did you forget a prefix, or is the file not yet committed?
162 js/src/tests/style/BadIncludes.h:8: error:
163 <tests/style/BadIncludes2.h> should be included using
164 the #include "..." form
166 js/src/tests/style/BadIncludes.h:10: error:
167 "stdio.h" is included using the wrong path;
168 did you forget a prefix, or is the file not yet committed?
170 js/src/tests/style/BadIncludes2.h:1: error:
171 vanilla header includes an inline-header file "tests/style/BadIncludes2-inl.h"
173 js/src/tests/style/BadIncludesOrder-inl.h:5:6: error:
174 "vm/JSScript-inl.h" should be included after "vm/Interpreter-inl.h"
176 js/src/tests/style/BadIncludesOrder-inl.h:6:7: error:
177 "vm/Interpreter-inl.h" should be included after "js/Value.h"
179 js/src/tests/style/BadIncludesOrder-inl.h:7:8: error:
180 "js/Value.h" should be included after "ds/LifoAlloc.h"
182 js/src/tests/style/BadIncludesOrder-inl.h:8:9: error:
183 "ds/LifoAlloc.h" should be included after "jsapi.h"
185 js/src/tests/style/BadIncludesOrder-inl.h:9:10: error:
186 "jsapi.h" should be included after <stdio.h>
188 js/src/tests/style/BadIncludesOrder-inl.h:10:11: error:
189 <stdio.h> should be included after "mozilla/HashFunctions.h"
191 js/src/tests/style/BadIncludesOrder-inl.h:28:29: error:
192 "vm/JSScript.h" should be included after "vm/JSFunction.h"
194 (multiple files): error:
195 header files form one or more cycles
197 tests/style/HeaderCycleA1.h
198 -> tests/style/HeaderCycleA2.h
199 -> tests/style/HeaderCycleA3.h
200 -> tests/style/HeaderCycleA1.h
202 tests/style/HeaderCycleB1-inl.h
203 -> tests/style/HeaderCycleB2-inl.h
204 -> tests/style/HeaderCycleB3-inl.h
205 -> tests/style/HeaderCycleB4-inl.h
206 -> tests/style/HeaderCycleB1-inl.h
207 -> tests/style/jsheadercycleB5inlines.h
208 -> tests/style/HeaderCycleB1-inl.h
209 -> tests/style/HeaderCycleB4-inl.h
220 actual_output
.append(line
+ "\n")
223 def error(filename
, linenum
, *lines
):
225 if linenum
is not None:
226 location
+= ":" + str(linenum
)
227 out(location
+ ": error:")
233 class FileKind(object):
243 if filename
.endswith(".c"):
246 if filename
.endswith(".cpp"):
249 if filename
.endswith(("inlines.h", "-inl.h")):
250 return FileKind
.INL_H
252 if filename
.endswith(".h"):
255 if filename
.endswith(".tbl"):
258 if filename
.endswith(".msg"):
261 error(filename
, None, "unknown file kind")
264 def check_style(enable_fixup
):
265 # We deal with two kinds of name.
266 # - A "filename" is a full path to a file from the repository root.
267 # - An "inclname" is how a file is referred to in a #include statement.
269 # Examples (filename -> inclname)
270 # - "mfbt/Attributes.h" -> "mozilla/Attributes.h"
271 # - "mozglue/misc/TimeStamp.h -> "mozilla/TimeStamp.h"
272 # - "memory/mozalloc/mozalloc.h -> "mozilla/mozalloc.h"
273 # - "js/public/Vector.h" -> "js/Vector.h"
274 # - "js/src/vm/String.h" -> "vm/String.h"
282 non_js_inclnames
= set() # type: set(inclname)
283 js_names
= dict() # type: dict(filename, inclname)
285 # Process files in js/src.
286 js_src_root
= os
.path
.join("js", "src")
287 for dirpath
, dirnames
, filenames
in os
.walk(js_src_root
):
288 if dirpath
== js_src_root
:
289 # Skip any subdirectories that contain a config.status file
292 for dirname
in dirnames
:
293 path
= os
.path
.join(dirpath
, dirname
, "config.status")
294 if os
.path
.isfile(path
):
295 builddirs
.append(dirname
)
296 for dirname
in builddirs
:
297 dirnames
.remove(dirname
)
298 for filename
in filenames
:
299 filepath
= os
.path
.join(dirpath
, filename
).replace("\\", "/")
300 if not filepath
.startswith(
301 tuple(ignored_js_src_dirs
)
302 ) and filepath
.endswith((".c", ".cpp", ".h", ".tbl", ".msg")):
303 inclname
= filepath
[len("js/src/") :]
304 js_names
[filepath
] = inclname
306 # Look for header files in directories in non_js_dirnames.
307 for non_js_dir
in non_js_dirnames
:
308 for dirpath
, dirnames
, filenames
in os
.walk(non_js_dir
):
309 for filename
in filenames
:
310 if filename
.endswith(".h"):
311 inclname
= "mozilla/" + filename
312 if non_js_dir
== "intl/components/":
313 inclname
= "mozilla/intl/" + filename
314 non_js_inclnames
.add(inclname
)
316 # Look for header files in js/public.
317 js_public_root
= os
.path
.join("js", "public")
318 for dirpath
, dirnames
, filenames
in os
.walk(js_public_root
):
319 for filename
in filenames
:
320 if filename
.endswith((".h", ".msg")):
321 filepath
= os
.path
.join(dirpath
, filename
).replace("\\", "/")
322 inclname
= "js/" + filepath
[len("js/public/") :]
323 js_names
[filepath
] = inclname
325 all_inclnames
= non_js_inclnames |
set(js_names
.values())
327 edges
= dict() # type: dict(inclname, set(inclname))
329 # We don't care what's inside the MFBT and MOZALLOC files, but because they
330 # are #included from JS files we have to add them to the inclusion graph.
331 for inclname
in non_js_inclnames
:
332 edges
[inclname
] = set()
334 # Process all the JS files.
335 for filename
in sorted(js_names
.keys()):
336 inclname
= js_names
[filename
]
337 file_kind
= FileKind
.get(filename
)
339 file_kind
== FileKind
.C
340 or file_kind
== FileKind
.CPP
341 or file_kind
== FileKind
.H
342 or file_kind
== FileKind
.INL_H
344 included_h_inclnames
= set() # type: set(inclname)
346 with
open(filename
, encoding
="utf-8") as f
:
350 code
= code
.sorted(inclname
)
351 with
open(filename
, "w") as f
:
352 f
.write(code
.to_source())
355 filename
, inclname
, file_kind
, code
, all_inclnames
, included_h_inclnames
358 edges
[inclname
] = included_h_inclnames
360 find_cycles(all_inclnames
, edges
)
362 # Compare expected and actual output.
363 difflines
= difflib
.unified_diff(
366 fromfile
="check_spidermonkey_style.py expected output",
367 tofile
="check_spidermonkey_style.py actual output",
370 for diffline
in difflines
:
372 print(diffline
, end
="")
377 def module_name(name
):
378 """Strip the trailing .cpp, .h, inlines.h or -inl.h from a filename."""
381 name
.replace("inlines.h", "")
382 .replace("-inl.h", "")
388 def is_module_header(enclosing_inclname
, header_inclname
):
389 """Determine if an included name is the "module header", i.e. should be
390 first in the file."""
392 module
= module_name(enclosing_inclname
)
394 # Normal case, for example:
395 # module == "vm/Runtime", header_inclname == "vm/Runtime.h".
396 if module
== module_name(header_inclname
):
399 # A public header, for example:
401 # module == "vm/CharacterEncoding",
402 # header_inclname == "js/CharacterEncoding.h"
404 # or (for implementation files for js/public/*/*.h headers)
406 # module == "vm/SourceHook",
407 # header_inclname == "js/experimental/SourceHook.h"
408 m
= re
.match(r
"js\/.*?([^\/]+)\.h", header_inclname
)
409 if m
is not None and module
.endswith("/" + m
.group(1)):
415 class Include(object):
416 """Important information for a single #include statement."""
418 def __init__(self
, include_prefix
, inclname
, line_suffix
, linenum
, is_system
):
419 self
.include_prefix
= include_prefix
420 self
.line_suffix
= line_suffix
421 self
.inclname
= inclname
422 self
.linenum
= linenum
423 self
.is_system
= is_system
425 def is_style_relevant(self
):
426 # Includes are style-relevant; that is, they're checked by the pairwise
427 # style-checking algorithm in check_file.
430 def section(self
, enclosing_inclname
):
431 """Identify which section inclname belongs to.
433 The section numbers are as follows.
434 0. Module header (e.g. jsfoo.h or jsfooinlines.h within jsfoo.cpp)
437 3. jsfoo.h, prmjtime.h, etc
441 7. non-.h, e.g. *.tbl, *.msg (these can be scattered throughout files)
447 if not self
.inclname
.endswith(".h"):
450 # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need
452 if is_module_header(enclosing_inclname
, self
.inclname
):
455 if "/" in self
.inclname
:
456 if self
.inclname
.startswith("mozilla/"):
459 if self
.inclname
.endswith("-inl.h"):
464 if self
.inclname
.endswith("inlines.h"):
471 return "<" + self
.inclname
+ ">"
473 return '"' + self
.inclname
+ '"'
475 def sort_key(self
, enclosing_inclname
):
476 return (self
.section(enclosing_inclname
), self
.inclname
.lower())
479 return self
.include_prefix
+ self
.quote() + self
.line_suffix
+ "\n"
482 class CppBlock(object):
483 """C preprocessor block: a whole file or a single #if/#elif/#else block.
485 A #if/#endif block is the contents of a #if/#endif (or similar) section.
486 The top-level block, which is not within a #if/#endif pair, is also
489 Each kid is either an Include (representing a #include), OrdinaryCode, or
490 a nested CppBlock."""
492 def __init__(self
, start_line
=""):
493 self
.start
= start_line
497 def is_style_relevant(self
):
500 def append_ordinary_line(self
, line
):
501 if len(self
.kids
) == 0 or not isinstance(self
.kids
[-1], OrdinaryCode
):
502 self
.kids
.append(OrdinaryCode())
503 self
.kids
[-1].lines
.append(line
)
505 def style_relevant_kids(self
):
506 """ Return a list of kids in this block that are style-relevant. """
507 return [kid
for kid
in self
.kids
if kid
.is_style_relevant()]
509 def sorted(self
, enclosing_inclname
):
510 """Return a hopefully-sorted copy of this block. Implements --fixup.
512 When in doubt, this leaves the code unchanged.
515 def pretty_sorted_includes(includes
):
516 """Return a new list containing the given includes, in order,
517 with blank lines separating sections."""
518 keys
= [inc
.sort_key(enclosing_inclname
) for inc
in includes
]
519 if sorted(keys
) == keys
:
520 return includes
# if nothing is out of order, don't touch anything
523 current_section
= None
524 for (section
, _
), inc
in sorted(zip(keys
, includes
)):
525 if current_section
is not None and section
!= current_section
:
526 output
.append(OrdinaryCode(["\n"])) # blank line
528 current_section
= section
531 def should_try_to_sort(includes
):
532 if "tests/style/BadIncludes" in enclosing_inclname
:
533 return False # don't straighten the counterexample
534 if any(inc
.inclname
in oddly_ordered_inclnames
for inc
in includes
):
535 return False # don't sort batches containing odd includes
536 if includes
== sorted(
537 includes
, key
=lambda inc
: inc
.sort_key(enclosing_inclname
)
539 return False # it's already sorted, avoid whitespace-only fixups
542 # The content of the eventual output of this method.
545 # The current batch of includes to sort. This list only ever contains Include objects
546 # and whitespace OrdinaryCode objects.
550 """Sort the contents of `batch` and move it to `output`."""
553 isinstance(item
, Include
)
554 or (isinstance(item
, OrdinaryCode
) and "".join(item
.lines
).isspace())
558 # Here we throw away the blank lines.
559 # `pretty_sorted_includes` puts them back.
561 last_include_index
= -1
562 for i
, item
in enumerate(batch
):
563 if isinstance(item
, Include
):
564 includes
.append(item
)
565 last_include_index
= i
566 cutoff
= last_include_index
+ 1
568 if should_try_to_sort(includes
):
569 output
.extend(pretty_sorted_includes(includes
) + batch
[cutoff
:])
574 for kid
in self
.kids
:
575 if isinstance(kid
, CppBlock
):
577 output
.append(kid
.sorted(enclosing_inclname
))
578 elif isinstance(kid
, Include
):
581 assert isinstance(kid
, OrdinaryCode
)
582 if kid
.to_source().isspace():
590 result
.start
= self
.start
591 result
.end
= self
.end
596 return self
.start
+ "".join(kid
.to_source() for kid
in self
.kids
) + self
.end
599 class OrdinaryCode(object):
600 """ A list of lines of code that aren't #include/#if/#else/#endif lines. """
602 def __init__(self
, lines
=None):
603 self
.lines
= lines
if lines
is not None else []
605 def is_style_relevant(self
):
609 return "".join(self
.lines
)
612 # A "snippet" is one of:
614 # * Include - representing an #include line
615 # * CppBlock - a whole file or #if/#elif/#else block; contains a list of snippets
616 # * OrdinaryCode - representing lines of non-#include-relevant code
620 block_stack
= [CppBlock()]
622 # Extract the #include statements as a tree of snippets.
623 for linenum
, line
in enumerate(f
, start
=1):
624 if line
.lstrip().startswith("#"):
625 # Look for a |#include "..."| line.
626 m
= re
.match(r
'(\s*#\s*include\s+)"([^"]*)"(.*)', line
)
628 prefix
, inclname
, suffix
= m
.groups()
629 block_stack
[-1].kids
.append(
630 Include(prefix
, inclname
, suffix
, linenum
, is_system
=False)
634 # Look for a |#include <...>| line.
635 m
= re
.match(r
"(\s*#\s*include\s+)<([^>]*)>(.*)", line
)
637 prefix
, inclname
, suffix
= m
.groups()
638 block_stack
[-1].kids
.append(
639 Include(prefix
, inclname
, suffix
, linenum
, is_system
=True)
643 # Look for a |#{if,ifdef,ifndef}| line.
644 m
= re
.match(r
"\s*#\s*(if|ifdef|ifndef)\b", line
)
647 new_block
= CppBlock(line
)
648 block_stack
[-1].kids
.append(new_block
)
649 block_stack
.append(new_block
)
652 # Look for a |#{elif,else}| line.
653 m
= re
.match(r
"\s*#\s*(elif|else)\b", line
)
655 # Close the current block, and open an adjacent one.
657 new_block
= CppBlock(line
)
658 block_stack
[-1].kids
.append(new_block
)
659 block_stack
.append(new_block
)
662 # Look for a |#endif| line.
663 m
= re
.match(r
"\s*#\s*endif\b", line
)
665 # Close the current block.
666 block_stack
.pop().end
= line
667 if len(block_stack
) == 0:
668 raise ValueError("#endif without #if at line " + str(linenum
))
671 # Otherwise, we have an ordinary line.
672 block_stack
[-1].append_ordinary_line(line
)
674 if len(block_stack
) > 1:
675 raise ValueError("unmatched #if")
676 return block_stack
[-1]
680 filename
, inclname
, file_kind
, code
, all_inclnames
, included_h_inclnames
682 def check_include_statement(include
):
683 """Check the style of a single #include statement."""
685 if include
.is_system
:
686 # Check it is not a known local file (in which case it's probably a system header).
688 include
.inclname
in included_inclnames_to_ignore
689 or include
.inclname
in all_inclnames
694 include
.quote() + " should be included using",
695 'the #include "..." form',
699 if include
.inclname
not in included_inclnames_to_ignore
:
700 included_kind
= FileKind
.get(include
.inclname
)
702 # Check the #include path has the correct form.
703 if include
.inclname
not in all_inclnames
:
707 include
.quote() + " is included using the wrong path;",
708 "did you forget a prefix, or is the file not yet committed?",
711 # Record inclusions of .h files for cycle detection later.
712 # (Exclude .tbl and .msg files.)
713 elif included_kind
== FileKind
.H
or included_kind
== FileKind
.INL_H
:
714 included_h_inclnames
.add(include
.inclname
)
716 # Check a H file doesn't #include an INL_H file.
717 if file_kind
== FileKind
.H
and included_kind
== FileKind
.INL_H
:
721 "vanilla header includes an inline-header file "
725 # Check a file doesn't #include itself. (We do this here because the cycle
726 # detection below doesn't detect this case.)
727 if inclname
== include
.inclname
:
728 error(filename
, include
.linenum
, "the file includes itself")
730 def check_includes_order(include1
, include2
):
731 """Check the ordering of two #include statements."""
734 include1
.inclname
in oddly_ordered_inclnames
735 or include2
.inclname
in oddly_ordered_inclnames
739 section1
= include1
.section(inclname
)
740 section2
= include2
.section(inclname
)
741 if (section1
> section2
) or (
742 (section1
== section2
)
743 and (include1
.inclname
.lower() > include2
.inclname
.lower())
747 str(include1
.linenum
) + ":" + str(include2
.linenum
),
748 include1
.quote() + " should be included after " + include2
.quote(),
751 # Check the extracted #include statements, both individually, and the ordering of
752 # adjacent pairs that live in the same block.
753 def pair_traverse(prev
, this
):
754 if isinstance(this
, Include
):
755 check_include_statement(this
)
756 if isinstance(prev
, Include
):
757 check_includes_order(prev
, this
)
759 kids
= this
.style_relevant_kids()
760 for prev2
, this2
in zip([None] + kids
[0:-1], kids
):
761 pair_traverse(prev2
, this2
)
763 pair_traverse(None, code
)
766 def find_cycles(all_inclnames
, edges
):
767 """Find and draw any cycles."""
769 SCCs
= tarjan(all_inclnames
, edges
)
771 # The various sorted() calls below ensure the output is deterministic.
778 out(" " * indent
+ ("-> " if indent
else " ") + v
)
782 for succ
in sorted(edges
[v
]):
784 draw(succ
, indent
+ 1)
786 draw(sorted(c
)[0], 0)
789 have_drawn_an_SCC
= False
790 for scc
in sorted(SCCs
):
792 if not have_drawn_an_SCC
:
793 error("(multiple files)", None, "header files form one or more cycles")
794 have_drawn_an_SCC
= True
799 # Tarjan's algorithm for finding the strongly connected components (SCCs) of a graph.
800 # https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
808 def strongconnect(v
, index
):
809 # Set the depth index for v to the smallest unused index
810 vertex_index
[v
] = index
811 vertex_lowlink
[v
] = index
815 # Consider successors of v
817 if w
not in vertex_index
:
818 # Successor w has not yet been visited; recurse on it
819 index
= strongconnect(w
, index
)
820 vertex_lowlink
[v
] = min(vertex_lowlink
[v
], vertex_lowlink
[w
])
822 # Successor w is in stack S and hence in the current SCC
823 vertex_lowlink
[v
] = min(vertex_lowlink
[v
], vertex_index
[w
])
825 # If v is a root node, pop the stack and generate an SCC
826 if vertex_lowlink
[v
] == vertex_index
[v
]:
835 if v
not in vertex_index
:
836 index
= strongconnect(v
, index
)
842 if sys
.argv
[1:] == ["--fixup"]:
843 # Sort #include directives in-place. Fixup mode doesn't solve
844 # all possible silliness that the script checks for; it's just a
845 # hack for the common case where renaming a header causes style
848 elif sys
.argv
[1:] == []:
852 "TEST-UNEXPECTED-FAIL | check_spidermonkey_style.py | unexpected command "
853 "line options: " + repr(sys
.argv
[1:])
857 ok
= check_style(fixup
)
860 print("TEST-PASS | check_spidermonkey_style.py | ok")
863 "TEST-UNEXPECTED-FAIL | check_spidermonkey_style.py | "
864 + "actual output does not match expected output; diff is above."
867 "TEST-UNEXPECTED-FAIL | check_spidermonkey_style.py | "
868 + "Hint: If the problem is that you renamed a header, and many #includes "
869 + "are no longer in alphabetical order, commit your work and then try "
870 + "`check_spidermonkey_style.py --fixup`. "
871 + "You need to commit first because --fixup modifies your files in place."
874 sys
.exit(0 if ok
else 1)
877 if __name__
== "__main__":