9
9
Usage:
10
10
11
11
% utils/update_cc_test_checks.py --llvm-bin=release/bin test/a.cc
12
- % utils/update_cc_test_checks.py --c-index-test=release/bin/c-index-test \
13
- --clang=release/bin/clang /tmp/c/a.cc
12
+ % utils/update_cc_test_checks.py --clang=release/bin/clang /tmp/c/a.cc
14
13
'''
15
14
16
15
import argparse
17
16
import collections
18
17
import distutils .spawn
18
+ import json
19
19
import os
20
20
import shlex
21
21
import string
38
38
}
39
39
40
40
def get_line2spell_and_mangled (args , clang_args ):
41
+ def debug_mangled (* print_args , ** kwargs ):
42
+ if args .verbose :
43
+ print (* print_args , file = sys .stderr , ** kwargs )
41
44
ret = {}
42
- with tempfile .NamedTemporaryFile () as f :
43
- # TODO Make c-index-test print mangled names without circumventing through precompiled headers
44
- status = subprocess .run ([args .c_index_test , '-write-pch' , f .name , * clang_args ],
45
- stdout = subprocess .PIPE , stderr = subprocess .STDOUT )
46
- if status .returncode :
47
- sys .stderr .write (status .stdout .decode ())
48
- sys .exit (2 )
49
- output = subprocess .check_output ([args .c_index_test ,
50
- '-test-print-mangle' , f .name ])
51
- if sys .version_info [0 ] > 2 :
52
- output = output .decode ()
53
- DeclRE = re .compile (r'^FunctionDecl=(\w+):(\d+):\d+ \(Definition\)' )
54
- MangleRE = re .compile (r'.*\[mangled=([^]]+)\]' )
55
- MatchedDecl = False
56
- for line in output .splitlines ():
57
- # Get the function source name, line number and mangled name. Sometimes
58
- # c-index-test outputs the mangled name on a separate line (this can happen
59
- # with block comments in front of functions). Keep scanning until we see
60
- # the mangled name.
61
- decl_m = DeclRE .match (line )
62
- mangle_m = MangleRE .match (line )
63
-
64
- if decl_m :
65
- MatchedDecl = True
66
- spell , lineno = decl_m .groups ()
67
- if MatchedDecl and mangle_m :
68
- mangled = mangle_m .group (1 )
69
- MatchedDecl = False
70
- else :
45
+ # Use clang's JSON AST dump to get the mangled name
46
+ json_dump_args = [args .clang , * clang_args , '-fsyntax-only' , '-o' , '-' ]
47
+ if '-cc1' not in json_dump_args :
48
+ # For tests that invoke %clang instead if %clang_cc1 we have to use
49
+ # -Xclang -ast-dump=json instead:
50
+ json_dump_args .append ('-Xclang' )
51
+ json_dump_args .append ('-ast-dump=json' )
52
+ debug_mangled ('Running' , ' ' .join (json_dump_args ))
53
+ status = subprocess .run (json_dump_args , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
54
+ if status .returncode != 0 :
55
+ sys .stderr .write ('Failed to run ' + ' ' .join (json_dump_args ) + '\n ' )
56
+ sys .stderr .write (status .stderr .decode ())
57
+ sys .stderr .write (status .stdout .decode ())
58
+ sys .exit (2 )
59
+ ast = json .loads (status .stdout .decode ())
60
+ if ast ['kind' ] != 'TranslationUnitDecl' :
61
+ common .error ('Clang AST dump JSON format changed?' )
62
+ sys .exit (2 )
63
+
64
+ # Get the inner node and iterate over all children of type FunctionDecl.
65
+ # TODO: Should we add checks for global variables being emitted?
66
+ for node in ast ['inner' ]:
67
+ if node ['kind' ] != 'FunctionDecl' :
71
68
continue
72
-
73
- if mangled == '_' + spell :
74
- # HACK for MacOS (where the mangled name includes an _ for C but the IR won't):
75
- mangled = spell
76
- # Note -test-print-mangle does not print file names so if #include is used,
77
- # the line number may come from an included file.
78
- ret [int (lineno )- 1 ] = (spell , mangled )
69
+ if node .get ('isImplicit' ) is True and node .get ('storageClass' ) == 'extern' :
70
+ debug_mangled ('Skipping builtin function:' , node ['name' ], '@' , node ['loc' ])
71
+ continue
72
+ debug_mangled ('Found function:' , node ['kind' ], node ['name' ], '@' , node ['loc' ])
73
+ line = node ['loc' ].get ('line' )
74
+ # If there is no line it is probably a builtin function -> skip
75
+ if line is None :
76
+ debug_mangled ('Skipping function without line number:' , node ['name' ], '@' , node ['loc' ])
77
+ continue
78
+ spell = node ['name' ]
79
+ mangled = node .get ('mangledName' , spell )
80
+ ret [int (line )- 1 ] = (spell , mangled )
79
81
if args .verbose :
80
82
for line , func_name in sorted (ret .items ()):
81
83
print ('line {}: found function {}' .format (line + 1 , func_name ), file = sys .stderr )
84
+ if not ret :
85
+ common .warn ('Did not find any functions using' , ' ' .join (json_dump_args ))
82
86
return ret
83
87
84
88
@@ -92,8 +96,6 @@ def config():
92
96
help = '"clang" executable, defaults to $llvm_bin/clang' )
93
97
parser .add_argument ('--clang-args' ,
94
98
help = 'Space-separated extra args to clang, e.g. --clang-args=-v' )
95
- parser .add_argument ('--c-index-test' ,
96
- help = '"c-index-test" executable, defaults to $llvm_bin/c-index-test' )
97
99
parser .add_argument ('--opt' ,
98
100
help = '"opt" executable, defaults to $llvm_bin/opt' )
99
101
parser .add_argument (
@@ -140,15 +142,6 @@ def config():
140
142
# defer this error message until we find that opt is actually needed.
141
143
args .opt = None
142
144
143
- if args .c_index_test is None :
144
- if args .llvm_bin is None :
145
- args .c_index_test = 'c-index-test'
146
- else :
147
- args .c_index_test = os .path .join (args .llvm_bin , 'c-index-test' )
148
- if not distutils .spawn .find_executable (args .c_index_test ):
149
- print ('Please specify --llvm-bin or --c-index-test' , file = sys .stderr )
150
- sys .exit (1 )
151
-
152
145
return args
153
146
154
147
@@ -274,8 +267,8 @@ def main():
274
267
275
268
get_function_body (args , filename , clang_args , extra_commands , prefixes , triple_in_cmd , func_dict )
276
269
277
- # Invoke c-index-test to get mapping from start lines to mangled names.
278
- # Forward all clang args for now.
270
+ # Invoke clang -Xclang -ast-dump=json to get mapping from start lines to
271
+ # mangled names. Forward all clang args for now.
279
272
for k , v in get_line2spell_and_mangled (args , clang_args ).items ():
280
273
line2spell_and_mangled_list [k ].append (v )
281
274
0 commit comments