@@ 797-961 (lines=165) @@ | ||
794 | return s in GetNonHeaderExtensions() |
|
795 | ||
796 | ||
797 | class _IncludeState(object): |
|
798 | """Tracks line numbers for includes, and the order in which includes appear. |
|
799 | ||
800 | include_list contains list of lists of (header, line number) pairs. |
|
801 | It's a lists of lists rather than just one flat list to make it |
|
802 | easier to update across preprocessor boundaries. |
|
803 | ||
804 | Call CheckNextIncludeOrder() once for each header in the file, passing |
|
805 | in the type constants defined above. Calls in an illegal order will |
|
806 | raise an _IncludeError with an appropriate error message. |
|
807 | ||
808 | """ |
|
809 | # self._section will move monotonically through this set. If it ever |
|
810 | # needs to move backwards, CheckNextIncludeOrder will raise an error. |
|
811 | _INITIAL_SECTION = 0 |
|
812 | _MY_H_SECTION = 1 |
|
813 | _C_SECTION = 2 |
|
814 | _CPP_SECTION = 3 |
|
815 | _OTHER_H_SECTION = 4 |
|
816 | ||
817 | _TYPE_NAMES = { |
|
818 | _C_SYS_HEADER: 'C system header', |
|
819 | _CPP_SYS_HEADER: 'C++ system header', |
|
820 | _LIKELY_MY_HEADER: 'header this file implements', |
|
821 | _POSSIBLE_MY_HEADER: 'header this file may implement', |
|
822 | _OTHER_HEADER: 'other header', |
|
823 | } |
|
824 | _SECTION_NAMES = { |
|
825 | _INITIAL_SECTION: "... nothing. (This can't be an error.)", |
|
826 | _MY_H_SECTION: 'a header this file implements', |
|
827 | _C_SECTION: 'C system header', |
|
828 | _CPP_SECTION: 'C++ system header', |
|
829 | _OTHER_H_SECTION: 'other header', |
|
830 | } |
|
831 | ||
832 | def __init__(self): |
|
833 | self.include_list = [[]] |
|
834 | self._section = None |
|
835 | self._last_header = None |
|
836 | self.ResetSection('') |
|
837 | ||
838 | def FindHeader(self, header): |
|
839 | """Check if a header has already been included. |
|
840 | ||
841 | Args: |
|
842 | header: header to check. |
|
843 | Returns: |
|
844 | Line number of previous occurrence, or -1 if the header has not |
|
845 | been seen before. |
|
846 | """ |
|
847 | for section_list in self.include_list: |
|
848 | for f in section_list: |
|
849 | if f[0] == header: |
|
850 | return f[1] |
|
851 | return -1 |
|
852 | ||
853 | def ResetSection(self, directive): |
|
854 | """Reset section checking for preprocessor directive. |
|
855 | ||
856 | Args: |
|
857 | directive: preprocessor directive (e.g. "if", "else"). |
|
858 | """ |
|
859 | # The name of the current section. |
|
860 | self._section = self._INITIAL_SECTION |
|
861 | # The path of last found header. |
|
862 | self._last_header = '' |
|
863 | ||
864 | # Update list of includes. Note that we never pop from the |
|
865 | # include list. |
|
866 | if directive in ('if', 'ifdef', 'ifndef'): |
|
867 | self.include_list.append([]) |
|
868 | elif directive in ('else', 'elif'): |
|
869 | self.include_list[-1] = [] |
|
870 | ||
871 | def SetLastHeader(self, header_path): |
|
872 | self._last_header = header_path |
|
873 | ||
874 | def CanonicalizeAlphabeticalOrder(self, header_path): |
|
875 | """Returns a path canonicalized for alphabetical comparison. |
|
876 | ||
877 | - replaces "-" with "_" so they both cmp the same. |
|
878 | - removes '-inl' since we don't require them to be after the main header. |
|
879 | - lowercase everything, just in case. |
|
880 | ||
881 | Args: |
|
882 | header_path: Path to be canonicalized. |
|
883 | ||
884 | Returns: |
|
885 | Canonicalized path. |
|
886 | """ |
|
887 | return header_path.replace('-inl.h', '.h').replace('-', '_').lower() |
|
888 | ||
889 | def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): |
|
890 | """Check if a header is in alphabetical order with the previous header. |
|
891 | ||
892 | Args: |
|
893 | clean_lines: A CleansedLines instance containing the file. |
|
894 | linenum: The number of the line to check. |
|
895 | header_path: Canonicalized header to be checked. |
|
896 | ||
897 | Returns: |
|
898 | Returns true if the header is in alphabetical order. |
|
899 | """ |
|
900 | # If previous section is different from current section, _last_header will |
|
901 | # be reset to empty string, so it's always less than current header. |
|
902 | # |
|
903 | # If previous line was a blank line, assume that the headers are |
|
904 | # intentionally sorted the way they are. |
|
905 | if (self._last_header > header_path and |
|
906 | Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])): |
|
907 | return False |
|
908 | return True |
|
909 | ||
910 | def CheckNextIncludeOrder(self, header_type): |
|
911 | """Returns a non-empty error message if the next header is out of order. |
|
912 | ||
913 | This function also updates the internal state to be ready to check |
|
914 | the next include. |
|
915 | ||
916 | Args: |
|
917 | header_type: One of the _XXX_HEADER constants defined above. |
|
918 | ||
919 | Returns: |
|
920 | The empty string if the header is in the right order, or an |
|
921 | error message describing what's wrong. |
|
922 | ||
923 | """ |
|
924 | error_message = ('Found %s after %s' % |
|
925 | (self._TYPE_NAMES[header_type], |
|
926 | self._SECTION_NAMES[self._section])) |
|
927 | ||
928 | last_section = self._section |
|
929 | ||
930 | if header_type == _C_SYS_HEADER: |
|
931 | if self._section <= self._C_SECTION: |
|
932 | self._section = self._C_SECTION |
|
933 | else: |
|
934 | self._last_header = '' |
|
935 | return error_message |
|
936 | elif header_type == _CPP_SYS_HEADER: |
|
937 | if self._section <= self._CPP_SECTION: |
|
938 | self._section = self._CPP_SECTION |
|
939 | else: |
|
940 | self._last_header = '' |
|
941 | return error_message |
|
942 | elif header_type == _LIKELY_MY_HEADER: |
|
943 | if self._section <= self._MY_H_SECTION: |
|
944 | self._section = self._MY_H_SECTION |
|
945 | else: |
|
946 | self._section = self._OTHER_H_SECTION |
|
947 | elif header_type == _POSSIBLE_MY_HEADER: |
|
948 | if self._section <= self._MY_H_SECTION: |
|
949 | self._section = self._MY_H_SECTION |
|
950 | else: |
|
951 | # This will always be the fallback because we're not sure |
|
952 | # enough that the header is associated with this file. |
|
953 | self._section = self._OTHER_H_SECTION |
|
954 | else: |
|
955 | assert header_type == _OTHER_HEADER |
|
956 | self._section = self._OTHER_H_SECTION |
|
957 | ||
958 | if last_section != self._section: |
|
959 | self._last_header = '' |
|
960 | ||
961 | return '' |
|
962 | ||
963 | ||
964 | class _CppLintState(object): |
@@ 797-961 (lines=165) @@ | ||
794 | return s in GetNonHeaderExtensions() |
|
795 | ||
796 | ||
797 | class _IncludeState(object): |
|
798 | """Tracks line numbers for includes, and the order in which includes appear. |
|
799 | ||
800 | include_list contains list of lists of (header, line number) pairs. |
|
801 | It's a lists of lists rather than just one flat list to make it |
|
802 | easier to update across preprocessor boundaries. |
|
803 | ||
804 | Call CheckNextIncludeOrder() once for each header in the file, passing |
|
805 | in the type constants defined above. Calls in an illegal order will |
|
806 | raise an _IncludeError with an appropriate error message. |
|
807 | ||
808 | """ |
|
809 | # self._section will move monotonically through this set. If it ever |
|
810 | # needs to move backwards, CheckNextIncludeOrder will raise an error. |
|
811 | _INITIAL_SECTION = 0 |
|
812 | _MY_H_SECTION = 1 |
|
813 | _C_SECTION = 2 |
|
814 | _CPP_SECTION = 3 |
|
815 | _OTHER_H_SECTION = 4 |
|
816 | ||
817 | _TYPE_NAMES = { |
|
818 | _C_SYS_HEADER: 'C system header', |
|
819 | _CPP_SYS_HEADER: 'C++ system header', |
|
820 | _LIKELY_MY_HEADER: 'header this file implements', |
|
821 | _POSSIBLE_MY_HEADER: 'header this file may implement', |
|
822 | _OTHER_HEADER: 'other header', |
|
823 | } |
|
824 | _SECTION_NAMES = { |
|
825 | _INITIAL_SECTION: "... nothing. (This can't be an error.)", |
|
826 | _MY_H_SECTION: 'a header this file implements', |
|
827 | _C_SECTION: 'C system header', |
|
828 | _CPP_SECTION: 'C++ system header', |
|
829 | _OTHER_H_SECTION: 'other header', |
|
830 | } |
|
831 | ||
832 | def __init__(self): |
|
833 | self.include_list = [[]] |
|
834 | self._section = None |
|
835 | self._last_header = None |
|
836 | self.ResetSection('') |
|
837 | ||
838 | def FindHeader(self, header): |
|
839 | """Check if a header has already been included. |
|
840 | ||
841 | Args: |
|
842 | header: header to check. |
|
843 | Returns: |
|
844 | Line number of previous occurrence, or -1 if the header has not |
|
845 | been seen before. |
|
846 | """ |
|
847 | for section_list in self.include_list: |
|
848 | for f in section_list: |
|
849 | if f[0] == header: |
|
850 | return f[1] |
|
851 | return -1 |
|
852 | ||
853 | def ResetSection(self, directive): |
|
854 | """Reset section checking for preprocessor directive. |
|
855 | ||
856 | Args: |
|
857 | directive: preprocessor directive (e.g. "if", "else"). |
|
858 | """ |
|
859 | # The name of the current section. |
|
860 | self._section = self._INITIAL_SECTION |
|
861 | # The path of last found header. |
|
862 | self._last_header = '' |
|
863 | ||
864 | # Update list of includes. Note that we never pop from the |
|
865 | # include list. |
|
866 | if directive in ('if', 'ifdef', 'ifndef'): |
|
867 | self.include_list.append([]) |
|
868 | elif directive in ('else', 'elif'): |
|
869 | self.include_list[-1] = [] |
|
870 | ||
871 | def SetLastHeader(self, header_path): |
|
872 | self._last_header = header_path |
|
873 | ||
874 | def CanonicalizeAlphabeticalOrder(self, header_path): |
|
875 | """Returns a path canonicalized for alphabetical comparison. |
|
876 | ||
877 | - replaces "-" with "_" so they both cmp the same. |
|
878 | - removes '-inl' since we don't require them to be after the main header. |
|
879 | - lowercase everything, just in case. |
|
880 | ||
881 | Args: |
|
882 | header_path: Path to be canonicalized. |
|
883 | ||
884 | Returns: |
|
885 | Canonicalized path. |
|
886 | """ |
|
887 | return header_path.replace('-inl.h', '.h').replace('-', '_').lower() |
|
888 | ||
889 | def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): |
|
890 | """Check if a header is in alphabetical order with the previous header. |
|
891 | ||
892 | Args: |
|
893 | clean_lines: A CleansedLines instance containing the file. |
|
894 | linenum: The number of the line to check. |
|
895 | header_path: Canonicalized header to be checked. |
|
896 | ||
897 | Returns: |
|
898 | Returns true if the header is in alphabetical order. |
|
899 | """ |
|
900 | # If previous section is different from current section, _last_header will |
|
901 | # be reset to empty string, so it's always less than current header. |
|
902 | # |
|
903 | # If previous line was a blank line, assume that the headers are |
|
904 | # intentionally sorted the way they are. |
|
905 | if (self._last_header > header_path and |
|
906 | Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])): |
|
907 | return False |
|
908 | return True |
|
909 | ||
910 | def CheckNextIncludeOrder(self, header_type): |
|
911 | """Returns a non-empty error message if the next header is out of order. |
|
912 | ||
913 | This function also updates the internal state to be ready to check |
|
914 | the next include. |
|
915 | ||
916 | Args: |
|
917 | header_type: One of the _XXX_HEADER constants defined above. |
|
918 | ||
919 | Returns: |
|
920 | The empty string if the header is in the right order, or an |
|
921 | error message describing what's wrong. |
|
922 | ||
923 | """ |
|
924 | error_message = ('Found %s after %s' % |
|
925 | (self._TYPE_NAMES[header_type], |
|
926 | self._SECTION_NAMES[self._section])) |
|
927 | ||
928 | last_section = self._section |
|
929 | ||
930 | if header_type == _C_SYS_HEADER: |
|
931 | if self._section <= self._C_SECTION: |
|
932 | self._section = self._C_SECTION |
|
933 | else: |
|
934 | self._last_header = '' |
|
935 | return error_message |
|
936 | elif header_type == _CPP_SYS_HEADER: |
|
937 | if self._section <= self._CPP_SECTION: |
|
938 | self._section = self._CPP_SECTION |
|
939 | else: |
|
940 | self._last_header = '' |
|
941 | return error_message |
|
942 | elif header_type == _LIKELY_MY_HEADER: |
|
943 | if self._section <= self._MY_H_SECTION: |
|
944 | self._section = self._MY_H_SECTION |
|
945 | else: |
|
946 | self._section = self._OTHER_H_SECTION |
|
947 | elif header_type == _POSSIBLE_MY_HEADER: |
|
948 | if self._section <= self._MY_H_SECTION: |
|
949 | self._section = self._MY_H_SECTION |
|
950 | else: |
|
951 | # This will always be the fallback because we're not sure |
|
952 | # enough that the header is associated with this file. |
|
953 | self._section = self._OTHER_H_SECTION |
|
954 | else: |
|
955 | assert header_type == _OTHER_HEADER |
|
956 | self._section = self._OTHER_H_SECTION |
|
957 | ||
958 | if last_section != self._section: |
|
959 | self._last_header = '' |
|
960 | ||
961 | return '' |
|
962 | ||
963 | ||
964 | class _CppLintState(object): |