@@ 5656-5754 (lines=99) @@ | ||
5653 | return True |
|
5654 | ||
5655 | ||
5656 | def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, |
|
5657 | io=codecs): |
|
5658 | """Reports for missing stl includes. |
|
5659 | ||
5660 | This function will output warnings to make sure you are including the headers |
|
5661 | necessary for the stl containers and functions that you use. We only give one |
|
5662 | reason to include a header. For example, if you use both equal_to<> and |
|
5663 | less<> in a .h file, only one (the latter in the file) of these will be |
|
5664 | reported as a reason to include the <functional>. |
|
5665 | ||
5666 | Args: |
|
5667 | filename: The name of the current file. |
|
5668 | clean_lines: A CleansedLines instance containing the file. |
|
5669 | include_state: An _IncludeState instance. |
|
5670 | error: The function to call with any errors found. |
|
5671 | io: The IO factory to use to read the header file. Provided for unittest |
|
5672 | injection. |
|
5673 | """ |
|
5674 | required = {} # A map of header name to linenumber and the template entity. |
|
5675 | # Example of required: { '<functional>': (1219, 'less<>') } |
|
5676 | ||
5677 | for linenum in range(clean_lines.NumLines()): |
|
5678 | line = clean_lines.elided[linenum] |
|
5679 | if not line or line[0] == '#': |
|
5680 | continue |
|
5681 | ||
5682 | # String is special -- it is a non-templatized type in STL. |
|
5683 | matched = _RE_PATTERN_STRING.search(line) |
|
5684 | if matched: |
|
5685 | # Don't warn about strings in non-STL namespaces: |
|
5686 | # (We check only the first match per line; good enough.) |
|
5687 | prefix = line[:matched.start()] |
|
5688 | if prefix.endswith('std::') or not prefix.endswith('::'): |
|
5689 | required['<string>'] = (linenum, 'string') |
|
5690 | ||
5691 | for pattern, template, header in _re_pattern_headers_maybe_templates: |
|
5692 | if pattern.search(line): |
|
5693 | required[header] = (linenum, template) |
|
5694 | ||
5695 | # The following function is just a speed up, no semantics are changed. |
|
5696 | if not '<' in line: # Reduces the cpu time usage by skipping lines. |
|
5697 | continue |
|
5698 | ||
5699 | for pattern, template, header in _re_pattern_templates: |
|
5700 | matched = pattern.search(line) |
|
5701 | if matched: |
|
5702 | # Don't warn about IWYU in non-STL namespaces: |
|
5703 | # (We check only the first match per line; good enough.) |
|
5704 | prefix = line[:matched.start()] |
|
5705 | if prefix.endswith('std::') or not prefix.endswith('::'): |
|
5706 | required[header] = (linenum, template) |
|
5707 | ||
5708 | # The policy is that if you #include something in foo.h you don't need to |
|
5709 | # include it again in foo.cc. Here, we will look at possible includes. |
|
5710 | # Let's flatten the include_state include_list and copy it into a dictionary. |
|
5711 | include_dict = dict([item for sublist in include_state.include_list |
|
5712 | for item in sublist]) |
|
5713 | ||
5714 | # Did we find the header for this file (if any) and successfully load it? |
|
5715 | header_found = False |
|
5716 | ||
5717 | # Use the absolute path so that matching works properly. |
|
5718 | abs_filename = FileInfo(filename).FullName() |
|
5719 | ||
5720 | # For Emacs's flymake. |
|
5721 | # If cpplint is invoked from Emacs's flymake, a temporary file is generated |
|
5722 | # by flymake and that file name might end with '_flymake.cc'. In that case, |
|
5723 | # restore original file name here so that the corresponding header file can be |
|
5724 | # found. |
|
5725 | # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' |
|
5726 | # instead of 'foo_flymake.h' |
|
5727 | abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) |
|
5728 | ||
5729 | # include_dict is modified during iteration, so we iterate over a copy of |
|
5730 | # the keys. |
|
5731 | header_keys = list(include_dict.keys()) |
|
5732 | for header in header_keys: |
|
5733 | (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) |
|
5734 | fullpath = common_path + header |
|
5735 | if same_module and UpdateIncludeState(fullpath, include_dict, io): |
|
5736 | header_found = True |
|
5737 | ||
5738 | # If we can't find the header file for a .cc, assume it's because we don't |
|
5739 | # know where to look. In that case we'll give up as we're not sure they |
|
5740 | # didn't include it in the .h file. |
|
5741 | # TODO(unknown): Do a better job of finding .h files so we are confident that |
|
5742 | # not having the .h file means there isn't one. |
|
5743 | if not header_found: |
|
5744 | for extension in GetNonHeaderExtensions(): |
|
5745 | if filename.endswith('.' + extension): |
|
5746 | return |
|
5747 | ||
5748 | # All the lines have been processed, report the errors found. |
|
5749 | for required_header_unstripped in sorted(required, key=required.__getitem__): |
|
5750 | template = required[required_header_unstripped][1] |
|
5751 | if required_header_unstripped.strip('<>"') not in include_dict: |
|
5752 | error(filename, required[required_header_unstripped][0], |
|
5753 | 'build/include_what_you_use', 4, |
|
5754 | 'Add #include ' + required_header_unstripped + ' for ' + template) |
|
5755 | ||
5756 | ||
5757 | _RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') |
@@ 5656-5754 (lines=99) @@ | ||
5653 | return True |
|
5654 | ||
5655 | ||
5656 | def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, |
|
5657 | io=codecs): |
|
5658 | """Reports for missing stl includes. |
|
5659 | ||
5660 | This function will output warnings to make sure you are including the headers |
|
5661 | necessary for the stl containers and functions that you use. We only give one |
|
5662 | reason to include a header. For example, if you use both equal_to<> and |
|
5663 | less<> in a .h file, only one (the latter in the file) of these will be |
|
5664 | reported as a reason to include the <functional>. |
|
5665 | ||
5666 | Args: |
|
5667 | filename: The name of the current file. |
|
5668 | clean_lines: A CleansedLines instance containing the file. |
|
5669 | include_state: An _IncludeState instance. |
|
5670 | error: The function to call with any errors found. |
|
5671 | io: The IO factory to use to read the header file. Provided for unittest |
|
5672 | injection. |
|
5673 | """ |
|
5674 | required = {} # A map of header name to linenumber and the template entity. |
|
5675 | # Example of required: { '<functional>': (1219, 'less<>') } |
|
5676 | ||
5677 | for linenum in range(clean_lines.NumLines()): |
|
5678 | line = clean_lines.elided[linenum] |
|
5679 | if not line or line[0] == '#': |
|
5680 | continue |
|
5681 | ||
5682 | # String is special -- it is a non-templatized type in STL. |
|
5683 | matched = _RE_PATTERN_STRING.search(line) |
|
5684 | if matched: |
|
5685 | # Don't warn about strings in non-STL namespaces: |
|
5686 | # (We check only the first match per line; good enough.) |
|
5687 | prefix = line[:matched.start()] |
|
5688 | if prefix.endswith('std::') or not prefix.endswith('::'): |
|
5689 | required['<string>'] = (linenum, 'string') |
|
5690 | ||
5691 | for pattern, template, header in _re_pattern_headers_maybe_templates: |
|
5692 | if pattern.search(line): |
|
5693 | required[header] = (linenum, template) |
|
5694 | ||
5695 | # The following function is just a speed up, no semantics are changed. |
|
5696 | if not '<' in line: # Reduces the cpu time usage by skipping lines. |
|
5697 | continue |
|
5698 | ||
5699 | for pattern, template, header in _re_pattern_templates: |
|
5700 | matched = pattern.search(line) |
|
5701 | if matched: |
|
5702 | # Don't warn about IWYU in non-STL namespaces: |
|
5703 | # (We check only the first match per line; good enough.) |
|
5704 | prefix = line[:matched.start()] |
|
5705 | if prefix.endswith('std::') or not prefix.endswith('::'): |
|
5706 | required[header] = (linenum, template) |
|
5707 | ||
5708 | # The policy is that if you #include something in foo.h you don't need to |
|
5709 | # include it again in foo.cc. Here, we will look at possible includes. |
|
5710 | # Let's flatten the include_state include_list and copy it into a dictionary. |
|
5711 | include_dict = dict([item for sublist in include_state.include_list |
|
5712 | for item in sublist]) |
|
5713 | ||
5714 | # Did we find the header for this file (if any) and successfully load it? |
|
5715 | header_found = False |
|
5716 | ||
5717 | # Use the absolute path so that matching works properly. |
|
5718 | abs_filename = FileInfo(filename).FullName() |
|
5719 | ||
5720 | # For Emacs's flymake. |
|
5721 | # If cpplint is invoked from Emacs's flymake, a temporary file is generated |
|
5722 | # by flymake and that file name might end with '_flymake.cc'. In that case, |
|
5723 | # restore original file name here so that the corresponding header file can be |
|
5724 | # found. |
|
5725 | # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' |
|
5726 | # instead of 'foo_flymake.h' |
|
5727 | abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) |
|
5728 | ||
5729 | # include_dict is modified during iteration, so we iterate over a copy of |
|
5730 | # the keys. |
|
5731 | header_keys = list(include_dict.keys()) |
|
5732 | for header in header_keys: |
|
5733 | (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) |
|
5734 | fullpath = common_path + header |
|
5735 | if same_module and UpdateIncludeState(fullpath, include_dict, io): |
|
5736 | header_found = True |
|
5737 | ||
5738 | # If we can't find the header file for a .cc, assume it's because we don't |
|
5739 | # know where to look. In that case we'll give up as we're not sure they |
|
5740 | # didn't include it in the .h file. |
|
5741 | # TODO(unknown): Do a better job of finding .h files so we are confident that |
|
5742 | # not having the .h file means there isn't one. |
|
5743 | if not header_found: |
|
5744 | for extension in GetNonHeaderExtensions(): |
|
5745 | if filename.endswith('.' + extension): |
|
5746 | return |
|
5747 | ||
5748 | # All the lines have been processed, report the errors found. |
|
5749 | for required_header_unstripped in sorted(required, key=required.__getitem__): |
|
5750 | template = required[required_header_unstripped][1] |
|
5751 | if required_header_unstripped.strip('<>"') not in include_dict: |
|
5752 | error(filename, required[required_header_unstripped][0], |
|
5753 | 'build/include_what_you_use', 4, |
|
5754 | 'Add #include ' + required_header_unstripped + ' for ' + template) |
|
5755 | ||
5756 | ||
5757 | _RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') |