diagnostic_filter.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. # Copyright (C) 2016 YouCompleteMe contributors
  2. #
  3. # This file is part of YouCompleteMe.
  4. #
  5. # YouCompleteMe is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # YouCompleteMe is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
  17. import re
  18. class DiagnosticFilter:
  19. def __init__( self, config_or_filters ):
  20. self._filters : list = config_or_filters
  21. def IsAllowed( self, diagnostic ):
  22. return not any( filterMatches( diagnostic )
  23. for filterMatches in self._filters )
  24. @staticmethod
  25. def CreateFromOptions( user_options ):
  26. all_filters = user_options[ 'filter_diagnostics' ]
  27. compiled_by_type = {}
  28. for type_spec, filter_value in all_filters.items():
  29. filetypes = type_spec.split( ',' )
  30. for filetype in filetypes:
  31. compiled_by_type[ filetype ] = _CompileFilters( filter_value )
  32. return _MasterDiagnosticFilter( compiled_by_type )
  33. class _MasterDiagnosticFilter:
  34. def __init__( self, all_filters ):
  35. self._all_filters = all_filters
  36. self._cache = {}
  37. def SubsetForTypes( self, filetypes ):
  38. # check cache
  39. cache_key = ','.join( filetypes )
  40. cached = self._cache.get( cache_key )
  41. if cached is not None:
  42. return cached
  43. # build a new DiagnosticFilter merging all filters
  44. # for the provided filetypes
  45. spec = []
  46. for filetype in filetypes:
  47. type_specific = self._all_filters.get( filetype, [] )
  48. spec.extend( type_specific )
  49. new_filter = DiagnosticFilter( spec )
  50. self._cache[ cache_key ] = new_filter
  51. return new_filter
  52. def _ListOf( config_entry ):
  53. if isinstance( config_entry, list ):
  54. return config_entry
  55. return [ config_entry ]
  56. def CompileRegex( raw_regex ):
  57. pattern = re.compile( raw_regex, re.IGNORECASE )
  58. def FilterRegex( diagnostic ):
  59. return pattern.search( diagnostic[ 'text' ] ) is not None
  60. return FilterRegex
  61. def CompileLevel( level ):
  62. # valid kinds are WARNING and ERROR;
  63. # expected input levels are `warning` and `error`
  64. # NOTE: we don't validate the input...
  65. expected_kind = level.upper()
  66. def FilterLevel( diagnostic ):
  67. return diagnostic[ 'kind' ] == expected_kind
  68. return FilterLevel
  69. FILTER_COMPILERS = { 'regex' : CompileRegex,
  70. 'level' : CompileLevel }
  71. def _CompileFilters( config ):
  72. """Given a filter config dictionary, return a list of compiled filters"""
  73. filters = []
  74. for filter_type, filter_pattern in config.items():
  75. compiler = FILTER_COMPILERS.get( filter_type )
  76. if compiler is not None:
  77. for filter_config in _ListOf( filter_pattern ):
  78. compiledFilter = compiler( filter_config )
  79. filters.append( compiledFilter )
  80. return filters