diff options
Diffstat (limited to 'docs/tools')
-rw-r--r-- | docs/tools/clang.pod | 69 | ||||
-rw-r--r-- | docs/tools/dump_ast_matchers.py | 73 | ||||
-rw-r--r-- | docs/tools/dump_format_style.py | 143 |
3 files changed, 253 insertions, 32 deletions
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod index d2394a8..a58986c 100644 --- a/docs/tools/clang.pod +++ b/docs/tools/clang.pod @@ -7,7 +7,7 @@ clang - the Clang C, C++, and Objective-C compiler =head1 SYNOPSIS B<clang> [B<-c>|B<-S>|B<-E>] B<-std=>I<standard> B<-g> - [B<-O0>|B<-O1>|B<-O2>|B<-Os>|B<-Oz>|B<-O3>|B<-Ofast>|B<-O4>] + [B<-O0>|B<-O1>|B<-O2>|B<-O3>|B<-Ofast>|B<-Os>|B<-Oz>|B<-O>|B<-O4>] B<-W>I<warnings...> B<-pedantic> B<-I>I<dir...> B<-L>I<dir...> B<-D>I<macro[=defn]> @@ -81,7 +81,8 @@ B<Clang Static Analyzer> The Clang Static Analyzer is a tool that scans source code to try to find bugs through code analysis. This tool uses many parts of Clang and is built into the -same driver. +same driver. Please see L<http://clang-analyzer.llvm.org> for more details +on how to use the static analyzer. =head1 OPTIONS @@ -112,10 +113,6 @@ Run all of the above, plus the assembler, generating a target ".o" object file. If no stage selection option is specified, all stages above are run, and the linker is run to combine the results into an executable or shared library. -=item B<--analyze> - -Run the Clang Static Analyzer. - =back @@ -263,20 +260,52 @@ may not exist on earlier ones. =over -=item B<-O0> B<-O1> B<-O2> B<-Os> B<-Oz> B<-O3> B<-Ofast> B<-O4> - -Specify which optimization level to use. B<-O0> means "no optimization": this -level compiles the fastest and generates the most debuggable code. B<-O2> is a -moderate level of optimization which enables most optimizations. B<-Os> is like -B<-O2> with extra optimizations to reduce code size. B<-Oz> is like B<-Os> -(and thus B<-O2>), but reduces code size further. B<-O3> is like B<-O2>, -except that it enables optimizations that take longer to perform or that may -generate larger code (in an attempt to make the program run faster). -B<-Ofast> enables all the optimizations from B<-O3> along with other aggressive -optimizations that may violate strict compliance with language standards. On -supported platforms, B<-O4> enables link-time optimization; object files are -stored in the LLVM bitcode file format and whole program optimization is done at -link time. B<-O1> is somewhere between B<-O0> and B<-O2>. +=item B<-O0> B<-O1> B<-O2> B<-O3> B<-Ofast> B<-Os> B<-Oz> B<-O> B<-O4> + +Specify which optimization level to use: + +=over + +=item B<-O0> + +Means "no optimization": this level compiles the fastest and +generates the most debuggable code. + +=item B<-O1> + +Somewhere between B<-O0> and B<-O2>. + +=item B<-O2> + +Moderate level of optimization which enables most optimizations. + +=item B<-O3> + +Like B<-O2>, except that it enables optimizations that take longer to perform +or that may generate larger code (in an attempt to make the program run faster). + +=item B<-Ofast> + +Enables all the optimizations from B<-O3> along with other aggressive +optimizations that may violate strict compliance with language standards. + +=item B<-Os> + +Like B<-O2> with extra optimizations to reduce code size. + +=item B<-Oz> + +Like B<-Os> (and thus B<-O2>), but reduces code size further. + +=item B<-O> + +Equivalent to B<-O2>. + +=item B<-O4> and higher + +Currently equivalent to B<-O3> + +=back =item B<-g> diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py index 4ed6822..564dc38 100644 --- a/docs/tools/dump_ast_matchers.py +++ b/docs/tools/dump_ast_matchers.py @@ -154,20 +154,25 @@ def act_on_decl(declaration, comment, allowed_types): inner, name = m.groups() add_matcher('Type', name, 'Matcher<%s>...' % inner, comment, is_dyncast=True) - add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner, - comment, is_dyncast=True) + # FIXME: re-enable once we have implemented casting on the TypeLoc + # hierarchy. + # add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner, + # comment, is_dyncast=True) return m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\( \s*([^\s,]+\s*), - \s*(?:[^\s,]+\s*) + \s*(?:[^\s,]+\s*), + \s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\) \)\s*;\s*$""", declaration, flags=re.X) if m: - loc = m.group(1) - name = m.group(2) - result_types = extract_result_types(comment) - if not result_types: - raise Exception('Did not find allowed result types for: %s' % name) + loc, name, n_results, results = m.groups()[0:4] + result_types = [r.strip() for r in results.split(',')] + + comment_result_types = extract_result_types(comment) + if (comment_result_types and + sorted(result_types) != sorted(comment_result_types)): + raise Exception('Inconsistent documentation for: %s' % name) for result_type in result_types: add_matcher(result_type, name, 'Matcher<Type>', comment) if loc: @@ -175,7 +180,31 @@ def act_on_decl(declaration, comment, allowed_types): comment) return - m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)(?:_OVERLOAD)?\( + m = re.match(r"""^\s*AST_POLYMORPHIC_MATCHER(_P)?(.?)(?:_OVERLOAD)?\( + \s*([^\s,]+)\s*, + \s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\) + (?:,\s*([^\s,]+)\s* + ,\s*([^\s,]+)\s*)? + (?:,\s*([^\s,]+)\s* + ,\s*([^\s,]+)\s*)? + (?:,\s*\d+\s*)? + \)\s*{\s*$""", declaration, flags=re.X) + + if m: + p, n, name, n_results, results = m.groups()[0:5] + args = m.groups()[5:] + result_types = [r.strip() for r in results.split(',')] + if allowed_types and allowed_types != result_types: + raise Exception('Inconsistent documentation for: %s' % name) + if n not in ['', '2']: + raise Exception('Cannot parse "%s"' % declaration) + args = ', '.join('%s %s' % (args[i], args[i+1]) + for i in range(0, len(args), 2) if args[i]) + for result_type in result_types: + add_matcher(result_type, name, args, comment) + return + + m = re.match(r"""^\s*AST_MATCHER(_P)?(.?)(?:_OVERLOAD)?\( (?:\s*([^\s,]+)\s*,)? \s*([^\s,]+)\s* (?:,\s*([^\s,]+)\s* @@ -185,8 +214,8 @@ def act_on_decl(declaration, comment, allowed_types): (?:,\s*\d+\s*)? \)\s*{\s*$""", declaration, flags=re.X) if m: - p, n, result, name = m.groups()[1:5] - args = m.groups()[5:] + p, n, result, name = m.groups()[0:4] + args = m.groups()[4:] if not result: if not allowed_types: raise Exception('Did not find allowed result types for: %s' % name) @@ -201,6 +230,26 @@ def act_on_decl(declaration, comment, allowed_types): add_matcher(result_type, name, args, comment) return + # Parse ArgumentAdapting matchers. + m = re.match( + r"""^.*ArgumentAdaptingMatcherFunc<.*>\s*(?:LLVM_ATTRIBUTE_UNUSED\s*) + ([a-zA-Z]*)\s*=\s*{};$""", + declaration, flags=re.X) + if m: + name = m.groups()[0] + add_matcher('*', name, 'Matcher<*>', comment) + return + + # Parse Variadic operator matchers. + m = re.match( + r"""^.*VariadicOperatorMatcherFunc\s*([a-zA-Z]*)\s*=\s*{.*};$""", + declaration, flags=re.X) + if m: + name = m.groups()[0] + add_matcher('*', name, 'Matcher<*>, ..., Matcher<*>', comment) + return + + # Parse free standing matcher functions, like: # Matcher<ResultType> Name(Matcher<ArgumentType> InnerMatcher) { m = re.match(r"""^\s*(.*)\s+ @@ -270,7 +319,7 @@ for line in open(MATCHERS_FILE).read().splitlines(): declaration += ' ' + line if ((not line.strip()) or line.rstrip()[-1] == ';' or - line.rstrip()[-1] == '{'): + (line.rstrip()[-1] == '{' and line.rstrip()[-3:] != '= {')): if line.strip() and line.rstrip()[-1] == '{': body = True else: diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py new file mode 100644 index 0000000..0c8ca6d --- /dev/null +++ b/docs/tools/dump_format_style.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# A tool to parse the FormatStyle struct from Format.h and update the +# documentation in ../ClangFormatStyleOptions.rst automatically. +# Run from the directory in which this file is located to update the docs. + +import collections +import re +import urllib2 + +FORMAT_STYLE_FILE = '../../include/clang/Format/Format.h' +DOC_FILE = '../ClangFormatStyleOptions.rst' + + +def substitute(text, tag, contents): + replacement = '\n.. START_%s\n\n%s\n\n.. END_%s\n' % (tag, contents, tag) + pattern = r'\n\.\. START_%s\n.*\n\.\. END_%s\n' % (tag, tag) + return re.sub(pattern, '%s', text, flags=re.S) % replacement + +def doxygen2rst(text): + text = re.sub(r'<tt>\s*(.*?)\s*<\/tt>', r'``\1``', text) + text = re.sub(r'\\c ([^ ,;\.]+)', r'``\1``', text) + text = re.sub(r'\\\w+ ', '', text) + return text + +def indent(text, columns): + indent = ' ' * columns + s = re.sub(r'\n([^\n])', '\n' + indent + '\\1', text, flags=re.S) + if s.startswith('\n'): + return s + return indent + s + +class Option: + def __init__(self, name, type, comment): + self.name = name + self.type = type + self.comment = comment.strip() + self.enum = None + + def __str__(self): + s = '**%s** (``%s``)\n%s' % (self.name, self.type, + doxygen2rst(indent(self.comment, 2))) + if self.enum: + s += indent('\n\nPossible values:\n\n%s\n' % self.enum, 2) + return s + +class Enum: + def __init__(self, name, comment): + self.name = name + self.comment = comment.strip() + self.values = [] + + def __str__(self): + return '\n'.join(map(str, self.values)) + +class EnumValue: + def __init__(self, name, comment): + self.name = name + self.comment = comment.strip() + + def __str__(self): + return '* ``%s`` (in configuration: ``%s``)\n%s' % ( + self.name, + re.sub('.*_', '', self.name), + doxygen2rst(indent(self.comment, 2))) + +def clean_comment_line(line): + return line[3:].strip() + '\n' + +def read_options(header): + class State: + BeforeStruct, Finished, InStruct, InFieldComment, InEnum, \ + InEnumMemberComment = range(6) + state = State.BeforeStruct + + options = [] + enums = {} + comment = '' + enum = None + + for line in header: + line = line.strip() + if state == State.BeforeStruct: + if line == 'struct FormatStyle {': + state = State.InStruct + elif state == State.InStruct: + if line.startswith('///'): + state = State.InFieldComment + comment = clean_comment_line(line) + elif line == '};': + state = State.Finished + break + elif state == State.InFieldComment: + if line.startswith('///'): + comment += clean_comment_line(line) + elif line.startswith('enum'): + state = State.InEnum + name = re.sub(r'enum\s+(\w+)\s*\{', '\\1', line) + enum = Enum(name, comment) + elif line.endswith(';'): + state = State.InStruct + field_type, field_name = re.match(r'(\w+)\s+(\w+);', line).groups() + option = Option(str(field_name), str(field_type), comment) + options.append(option) + else: + raise Exception('Invalid format, expected comment, field or enum') + elif state == State.InEnum: + if line.startswith('///'): + state = State.InEnumMemberComment + comment = clean_comment_line(line) + elif line == '};': + state = State.InStruct + enums[enum.name] = enum + else: + raise Exception('Invalid format, expected enum field comment or };') + elif state == State.InEnumMemberComment: + if line.startswith('///'): + comment += clean_comment_line(line) + else: + state = State.InEnum + enum.values.append(EnumValue(line.replace(',', ''), comment)) + if state != State.Finished: + raise Exception('Not finished by the end of file') + + for option in options: + if not option.type in ['bool', 'unsigned', 'int']: + if enums.has_key(option.type): + option.enum = enums[option.type] + else: + raise Exception('Unknown type: %s' % option.type) + return options + +options = read_options(open(FORMAT_STYLE_FILE)) + +options = sorted(options, key=lambda x: x.name) +options_text = '\n\n'.join(map(str, options)) + +contents = open(DOC_FILE).read() + +contents = substitute(contents, 'FORMAT_STYLE_OPTIONS', options_text) + +with open(DOC_FILE, 'w') as output: + output.write(contents) + |