示例#1
0
class ClangCompleter( Completer ):
  def __init__( self, user_options ):
    super( ClangCompleter, self ).__init__( user_options )
    self._max_diagnostics_to_display = user_options[
      'max_diagnostics_to_display' ]
    self._completer = ycm_core.ClangCompleter()
    self._flags = Flags()
    self._diagnostic_store = None
    self._files_being_compiled = EphemeralValuesSet()


  def SupportedFiletypes( self ):
    return CLANG_FILETYPES


  def GetUnsavedFilesVector( self, request_data ):
    files = ycm_core.UnsavedFileVector()
    for filename, file_data in iteritems( request_data[ 'file_data' ] ):
      if not ClangAvailableForFiletypes( file_data[ 'filetypes' ] ):
        continue
      contents = file_data[ 'contents' ]
      if not contents or not filename:
        continue

      unsaved_file = ycm_core.UnsavedFile()
      utf8_contents = ToCppStringCompatible( contents )
      unsaved_file.contents_ = utf8_contents
      unsaved_file.length_ = len( utf8_contents )
      unsaved_file.filename_ = ToCppStringCompatible( filename )

      files.append( unsaved_file )
    return files


  def ComputeCandidatesInner( self, request_data ):
    filename = request_data[ 'filepath' ]
    if not filename:
      return

    if self._completer.UpdatingTranslationUnit(
        ToCppStringCompatible( filename ) ):
      raise RuntimeError( PARSING_FILE_MESSAGE )

    flags = self._FlagsForRequest( request_data )
    if not flags:
      raise RuntimeError( NO_COMPILE_FLAGS_MESSAGE )

    files = self.GetUnsavedFilesVector( request_data )
    line = request_data[ 'line_num' ]
    column = request_data[ 'start_column' ]
    with self._files_being_compiled.GetExclusive( filename ):
      results = self._completer.CandidatesForLocationInFile(
          ToCppStringCompatible( filename ),
          line,
          column,
          files,
          flags )

    if not results:
      raise RuntimeError( NO_COMPLETIONS_MESSAGE )

    return [ ConvertCompletionData( x ) for x in results ]


  def GetSubcommandsMap( self ):
    return {
      'GoToDefinition'           : ( lambda self, request_data, args:
         self._GoToDefinition( request_data ) ),
      'GoToDeclaration'          : ( lambda self, request_data, args:
         self._GoToDeclaration( request_data ) ),
      'GoTo'                     : ( lambda self, request_data, args:
         self._GoTo( request_data ) ),
      'GoToImprecise'            : ( lambda self, request_data, args:
         self._GoToImprecise( request_data ) ),
      'GoToInclude'              : ( lambda self, request_data, args:
         self._GoToInclude( request_data ) ),
      'ClearCompilationFlagCache': ( lambda self, request_data, args:
         self._ClearCompilationFlagCache() ),
      'GetType'                  : ( lambda self, request_data, args:
         self._GetSemanticInfo( request_data, func = 'GetTypeAtLocation' ) ),
      'GetTypeImprecise'         : ( lambda self, request_data, args:
         self._GetSemanticInfo( request_data,
                                func = 'GetTypeAtLocation',
                                reparse = False ) ),
      'GetParent'                : ( lambda self, request_data, args:
         self._GetSemanticInfo( request_data,
                                func = 'GetEnclosingFunctionAtLocation' ) ),
      'FixIt'                    : ( lambda self, request_data, args:
         self._FixIt( request_data ) ),
      'GetDoc'                   : ( lambda self, request_data, args:
         self._GetSemanticInfo( request_data,
                                reparse = True,
                                func = 'GetDocsForLocationInFile',
                                response_builder = _BuildGetDocResponse ) ),
      'GetDocImprecise'          : ( lambda self, request_data, args:
         self._GetSemanticInfo( request_data,
                                reparse = False,
                                func = 'GetDocsForLocationInFile',
                                response_builder = _BuildGetDocResponse ) ),
    }


  def _LocationForGoTo( self, goto_function, request_data, reparse = True ):
    filename = request_data[ 'filepath' ]
    if not filename:
      raise ValueError( INVALID_FILE_MESSAGE )

    flags = self._FlagsForRequest( request_data )
    if not flags:
      raise ValueError( NO_COMPILE_FLAGS_MESSAGE )

    files = self.GetUnsavedFilesVector( request_data )
    line = request_data[ 'line_num' ]
    column = request_data[ 'column_num' ]
    return getattr( self._completer, goto_function )(
        ToCppStringCompatible( filename ),
        line,
        column,
        files,
        flags,
        reparse )


  def _GoToDefinition( self, request_data ):
    location = self._LocationForGoTo( 'GetDefinitionLocation', request_data )
    if not location or not location.IsValid():
      raise RuntimeError( 'Can\'t jump to definition.' )
    return _ResponseForLocation( location )


  def _GoToDeclaration( self, request_data ):
    location = self._LocationForGoTo( 'GetDeclarationLocation', request_data )
    if not location or not location.IsValid():
      raise RuntimeError( 'Can\'t jump to declaration.' )
    return _ResponseForLocation( location )


  def _GoTo( self, request_data ):
    include_response = self._ResponseForInclude( request_data )
    if include_response:
      return include_response

    location = self._LocationForGoTo( 'GetDefinitionLocation', request_data )
    if not location or not location.IsValid():
      location = self._LocationForGoTo( 'GetDeclarationLocation', request_data )
    if not location or not location.IsValid():
      raise RuntimeError( 'Can\'t jump to definition or declaration.' )
    return _ResponseForLocation( location )


  def _GoToImprecise( self, request_data ):
    include_response = self._ResponseForInclude( request_data )
    if include_response:
      return include_response

    location = self._LocationForGoTo( 'GetDefinitionLocation',
                                      request_data,
                                      reparse = False )
    if not location or not location.IsValid():
      location = self._LocationForGoTo( 'GetDeclarationLocation',
                                        request_data,
                                        reparse = False )
    if not location or not location.IsValid():
      raise RuntimeError( 'Can\'t jump to definition or declaration.' )
    return _ResponseForLocation( location )


  def _ResponseForInclude( self, request_data ):
    """Returns response for include file location if cursor is on the
       include statement, None otherwise.
       Throws RuntimeError if cursor is on include statement and corresponding
       include file not found."""
    current_line = request_data[ 'line_value' ]
    include_file_name, quoted_include = GetIncludeStatementValue( current_line )
    if not include_file_name:
      return None

    current_file_path = request_data[ 'filepath' ]
    client_data = request_data.get( 'extra_conf_data', None )
    quoted_include_paths, include_paths = (
            self._flags.UserIncludePaths( current_file_path, client_data ) )
    if quoted_include:
      include_file_path = _GetAbsolutePath( include_file_name,
                                            quoted_include_paths )
      if include_file_path:
        return responses.BuildGoToResponse( include_file_path,
                                            line_num = 1,
                                            column_num = 1 )

    include_file_path = _GetAbsolutePath( include_file_name, include_paths )
    if include_file_path:
      return responses.BuildGoToResponse( include_file_path,
                                          line_num = 1,
                                          column_num = 1 )
    raise RuntimeError( 'Include file not found.' )


  def _GoToInclude( self, request_data ):
    include_response = self._ResponseForInclude( request_data )
    if not include_response:
      raise RuntimeError( 'Not an include/import line.' )
    return include_response


  def _GetSemanticInfo(
      self,
      request_data,
      func,
      response_builder = responses.BuildDisplayMessageResponse,
      reparse = True ):
    filename = request_data[ 'filepath' ]
    if not filename:
      raise ValueError( INVALID_FILE_MESSAGE )

    flags = self._FlagsForRequest( request_data )
    if not flags:
      raise ValueError( NO_COMPILE_FLAGS_MESSAGE )

    files = self.GetUnsavedFilesVector( request_data )
    line = request_data[ 'line_num' ]
    column = request_data[ 'column_num' ]

    message = getattr( self._completer, func )(
        ToCppStringCompatible( filename ),
        line,
        column,
        files,
        flags,
        reparse)

    if not message:
      message = "No semantic information available"

    return response_builder( message )

  def _ClearCompilationFlagCache( self ):
    self._flags.Clear()

  def _FixIt( self, request_data ):
    filename = request_data[ 'filepath' ]
    if not filename:
      raise ValueError( INVALID_FILE_MESSAGE )

    flags = self._FlagsForRequest( request_data )
    if not flags:
      raise ValueError( NO_COMPILE_FLAGS_MESSAGE )

    files = self.GetUnsavedFilesVector( request_data )
    line = request_data[ 'line_num' ]
    column = request_data[ 'column_num' ]

    fixits = getattr( self._completer, "GetFixItsForLocationInFile" )(
        ToCppStringCompatible( filename ),
        line,
        column,
        files,
        flags,
        True )

    # don't raise an error if not fixits: - leave that to the client to respond
    # in a nice way

    return responses.BuildFixItResponse( fixits )

  def OnFileReadyToParse( self, request_data ):
    filename = request_data[ 'filepath' ]
    if not filename:
      raise ValueError( INVALID_FILE_MESSAGE )

    flags = self._FlagsForRequest( request_data )
    if not flags:
      raise ValueError( NO_COMPILE_FLAGS_MESSAGE )

    with self._files_being_compiled.GetExclusive( filename ):
      diagnostics = self._completer.UpdateTranslationUnit(
        ToCppStringCompatible( filename ),
        self.GetUnsavedFilesVector( request_data ),
        flags )

    diagnostics = _FilterDiagnostics( diagnostics )
    self._diagnostic_store = DiagnosticsToDiagStructure( diagnostics )
    return [ responses.BuildDiagnosticData( x ) for x in
             diagnostics[ : self._max_diagnostics_to_display ] ]


  def OnBufferUnload( self, request_data ):
    self._completer.DeleteCachesForFile(
        ToCppStringCompatible( request_data[ 'filepath' ] ) )


  def GetDetailedDiagnostic( self, request_data ):
    current_line = request_data[ 'line_num' ]
    current_column = request_data[ 'column_num' ]
    current_file = request_data[ 'filepath' ]

    if not self._diagnostic_store:
      raise ValueError( NO_DIAGNOSTIC_MESSAGE )

    diagnostics = self._diagnostic_store[ current_file ][ current_line ]
    if not diagnostics:
      raise ValueError( NO_DIAGNOSTIC_MESSAGE )

    closest_diagnostic = None
    distance_to_closest_diagnostic = 999

    # FIXME: all of these calculations are currently working with byte
    # offsets, which are technically incorrect. We should be working with
    # codepoint offsets, as we want the nearest character-wise diagnostic
    for diagnostic in diagnostics:
      distance = abs( current_column - diagnostic.location_.column_number_ )
      if distance < distance_to_closest_diagnostic:
        distance_to_closest_diagnostic = distance
        closest_diagnostic = diagnostic

    return responses.BuildDisplayMessageResponse(
      closest_diagnostic.long_formatted_text_ )


  def DebugInfo( self, request_data ):
    filename = request_data[ 'filepath' ]
    try:
      extra_conf = extra_conf_store.ModuleFileForSourceFile( filename )
    except UnknownExtraConf as error:
      return ( 'C-family completer debug information:\n'
               '  Configuration file found but not loaded\n'
               '  Configuration path: {0}'.format(
                 error.extra_conf_file ) )

    try:
      # Note that it only raises NoExtraConfDetected:
      #  - when extra_conf is None and,
      #  - there is no compilation database
      flags = self._FlagsForRequest( request_data )
    except NoExtraConfDetected:
      # No flags
      return ( 'C-family completer debug information:\n'
               '  No configuration file found\n'
               '  No compilation database found' )

    # If _FlagsForRequest returns None or raises, we use an empty list in
    # practice.
    flags = flags or []

    if extra_conf:
      # We got the flags from the extra conf file
      return ( 'C-family completer debug information:\n'
               '  Configuration file found and loaded\n'
               '  Configuration path: {0}\n'
               '  Flags: {1}'.format( extra_conf, list( flags ) ) )

    try:
      database = self._flags.FindCompilationDatabase(
          os.path.dirname( filename ) )
    except NoCompilationDatabase:
      # No flags
      return ( 'C-family completer debug information:\n'
               '  No configuration file found\n'
               '  No compilation database found' )

    # We got the flags from the compilation database
    return ( 'C-family completer debug information:\n'
             '  No configuration file found\n'
             '  Using compilation database from: {0}\n'
             '  Flags: {1}'.format( database.database_directory,
                                    list( flags ) ) )


  def _FlagsForRequest( self, request_data ):
    filename = request_data[ 'filepath' ]
    if 'compilation_flags' in request_data:
      return PrepareFlagsForClang( request_data[ 'compilation_flags' ],
                                   filename )
    client_data = request_data.get( 'extra_conf_data', None )
    return self._flags.FlagsForFile( filename, client_data = client_data )
示例#2
0
class ClangCompleter(Completer):
    def __init__(self, user_options):
        super(ClangCompleter, self).__init__(user_options)
        self._max_diagnostics_to_display = user_options[
            'max_diagnostics_to_display']
        self._completer = ycm_core.ClangCompleter()
        self._flags = Flags()
        self._diagnostic_store = None
        self._files_being_compiled = EphemeralValuesSet()
        self._logger = logging.getLogger(__name__)

    def SupportedFiletypes(self):
        return CLANG_FILETYPES

    def GetUnsavedFilesVector(self, request_data):
        files = ycm_core.UnsavedFileVector()
        for filename, file_data in iteritems(request_data['file_data']):
            if not ClangAvailableForFiletypes(file_data['filetypes']):
                continue
            contents = file_data['contents']
            if not contents or not filename:
                continue

            unsaved_file = ycm_core.UnsavedFile()
            utf8_contents = ToCppStringCompatible(contents)
            unsaved_file.contents_ = utf8_contents
            unsaved_file.length_ = len(utf8_contents)
            unsaved_file.filename_ = ToCppStringCompatible(filename)

            files.append(unsaved_file)
        return files

    def ShouldCompleteIncludeStatement(self, request_data):
        column_codepoint = request_data['column_codepoint'] - 1
        current_line = request_data['line_value']
        return INCLUDE_REGEX.match(current_line[:column_codepoint])

    def ShouldUseNowInner(self, request_data):
        if self.ShouldCompleteIncludeStatement(request_data):
            return True
        return super(ClangCompleter, self).ShouldUseNowInner(request_data)

    def GetIncludePaths(self, request_data):
        column_codepoint = request_data['column_codepoint'] - 1
        current_line = request_data['line_value']
        line = current_line[:column_codepoint]
        path_dir, quoted_include, start_codepoint = (
            GetIncompleteIncludeValue(line))
        if start_codepoint is None:
            return None

        request_data['start_codepoint'] = start_codepoint

        # We do what GCC does for <> versus "":
        # http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html
        flags = self._FlagsForRequest(request_data)
        filepath = request_data['filepath']
        quoted_include_paths, include_paths = UserIncludePaths(flags, filepath)
        if quoted_include:
            include_paths.extend(quoted_include_paths)

        paths = []
        for include_path in include_paths:
            unicode_path = ToUnicode(os.path.join(include_path, path_dir))
            try:
                # We need to pass a unicode string to get unicode strings out of
                # listdir.
                relative_paths = os.listdir(unicode_path)
            except Exception:
                self._logger.exception('Error while listing %s folder.',
                                       unicode_path)
                relative_paths = []

            paths.extend(
                os.path.join(include_path, path_dir, relative_path)
                for relative_path in relative_paths)
        return paths

    def ComputeCandidatesInner(self, request_data):
        filename = request_data['filepath']
        if not filename:
            return

        paths = self.GetIncludePaths(request_data)
        if paths is not None:
            return GenerateCandidatesForPaths(paths)

        if self._completer.UpdatingTranslationUnit(
                ToCppStringCompatible(filename)):
            raise RuntimeError(PARSING_FILE_MESSAGE)

        flags = self._FlagsForRequest(request_data)
        if not flags:
            raise RuntimeError(NO_COMPILE_FLAGS_MESSAGE)

        files = self.GetUnsavedFilesVector(request_data)
        line = request_data['line_num']
        column = request_data['start_column']
        with self._files_being_compiled.GetExclusive(filename):
            results = self._completer.CandidatesForLocationInFile(
                ToCppStringCompatible(filename), line, column, files, flags)

        if not results:
            raise RuntimeError(NO_COMPLETIONS_MESSAGE)

        return [ConvertCompletionData(x) for x in results]

    def GetSubcommandsMap(self):
        return {
            'GoToDefinition': (lambda self, request_data, args: self.
                               _GoToDefinition(request_data)),
            'GoToDeclaration': (lambda self, request_data, args: self.
                                _GoToDeclaration(request_data)),
            'GoTo':
            (lambda self, request_data, args: self._GoTo(request_data)),
            'GoToImprecise':
            (lambda self, request_data, args: self._GoToImprecise(request_data)
             ),
            'GoToInclude':
            (lambda self, request_data, args: self._GoToInclude(request_data)),
            'ClearCompilationFlagCache': (lambda self, request_data, args: self
                                          ._ClearCompilationFlagCache()),
            'GetType': (lambda self, request_data, args: self._GetSemanticInfo(
                request_data, func='GetTypeAtLocation')),
            'GetTypeImprecise':
            (lambda self, request_data, args: self._GetSemanticInfo(
                request_data, func='GetTypeAtLocation', reparse=False)),
            'GetParent':
            (lambda self, request_data, args: self._GetSemanticInfo(
                request_data, func='GetEnclosingFunctionAtLocation')),
            'FixIt':
            (lambda self, request_data, args: self._FixIt(request_data)),
            'GetDoc': (lambda self, request_data, args: self._GetSemanticInfo(
                request_data,
                reparse=True,
                func='GetDocsForLocationInFile',
                response_builder=_BuildGetDocResponse)),
            'GetDocImprecise':
            (lambda self, request_data, args: self._GetSemanticInfo(
                request_data,
                reparse=False,
                func='GetDocsForLocationInFile',
                response_builder=_BuildGetDocResponse)),
        }

    def _LocationForGoTo(self, goto_function, request_data, reparse=True):
        filename = request_data['filepath']
        if not filename:
            raise ValueError(INVALID_FILE_MESSAGE)

        flags = self._FlagsForRequest(request_data)
        if not flags:
            raise ValueError(NO_COMPILE_FLAGS_MESSAGE)

        files = self.GetUnsavedFilesVector(request_data)
        line = request_data['line_num']
        column = request_data['column_num']
        return getattr(self._completer,
                       goto_function)(ToCppStringCompatible(filename), line,
                                      column, files, flags, reparse)

    def _GoToDefinition(self, request_data):
        location = self._LocationForGoTo('GetDefinitionLocation', request_data)
        if not location or not location.IsValid():
            raise RuntimeError('Can\'t jump to definition.')
        return _ResponseForLocation(location)

    def _GoToDeclaration(self, request_data):
        location = self._LocationForGoTo('GetDeclarationLocation',
                                         request_data)
        if not location or not location.IsValid():
            raise RuntimeError('Can\'t jump to declaration.')
        return _ResponseForLocation(location)

    def _GoTo(self, request_data):
        include_response = self._ResponseForInclude(request_data)
        if include_response:
            return include_response

        location = self._LocationForGoTo('GetDefinitionLocation', request_data)
        if not location or not location.IsValid():
            location = self._LocationForGoTo('GetDeclarationLocation',
                                             request_data)
        if not location or not location.IsValid():
            raise RuntimeError('Can\'t jump to definition or declaration.')
        return _ResponseForLocation(location)

    def _GoToImprecise(self, request_data):
        include_response = self._ResponseForInclude(request_data)
        if include_response:
            return include_response

        location = self._LocationForGoTo('GetDefinitionLocation',
                                         request_data,
                                         reparse=False)
        if not location or not location.IsValid():
            location = self._LocationForGoTo('GetDeclarationLocation',
                                             request_data,
                                             reparse=False)
        if not location or not location.IsValid():
            raise RuntimeError('Can\'t jump to definition or declaration.')
        return _ResponseForLocation(location)

    def _ResponseForInclude(self, request_data):
        """Returns response for include file location if cursor is on the
    include statement, None otherwise.
    Throws RuntimeError if cursor is on include statement and corresponding
    include file not found."""
        current_line = request_data['line_value']
        include_file_name, quoted_include = GetFullIncludeValue(current_line)
        if not include_file_name:
            return None

        flags = self._FlagsForRequest(request_data)
        current_file_path = request_data['filepath']
        quoted_include_paths, include_paths = UserIncludePaths(
            flags, current_file_path)
        if quoted_include:
            include_file_path = _GetAbsolutePath(include_file_name,
                                                 quoted_include_paths)
            if include_file_path:
                return responses.BuildGoToResponse(include_file_path,
                                                   line_num=1,
                                                   column_num=1)

        include_file_path = _GetAbsolutePath(include_file_name, include_paths)
        if include_file_path:
            return responses.BuildGoToResponse(include_file_path,
                                               line_num=1,
                                               column_num=1)
        raise RuntimeError('Include file not found.')

    def _GoToInclude(self, request_data):
        include_response = self._ResponseForInclude(request_data)
        if not include_response:
            raise RuntimeError('Not an include/import line.')
        return include_response

    def _GetSemanticInfo(
            self,
            request_data,
            func,
            response_builder=responses.BuildDisplayMessageResponse,
            reparse=True):
        filename = request_data['filepath']
        if not filename:
            raise ValueError(INVALID_FILE_MESSAGE)

        flags = self._FlagsForRequest(request_data)
        if not flags:
            raise ValueError(NO_COMPILE_FLAGS_MESSAGE)

        files = self.GetUnsavedFilesVector(request_data)
        line = request_data['line_num']
        column = request_data['column_num']

        message = getattr(self._completer,
                          func)(ToCppStringCompatible(filename), line, column,
                                files, flags, reparse)

        if not message:
            message = "No semantic information available"

        return response_builder(message)

    def _ClearCompilationFlagCache(self):
        self._flags.Clear()

    def _FixIt(self, request_data):
        filename = request_data['filepath']
        if not filename:
            raise ValueError(INVALID_FILE_MESSAGE)

        flags = self._FlagsForRequest(request_data)
        if not flags:
            raise ValueError(NO_COMPILE_FLAGS_MESSAGE)

        files = self.GetUnsavedFilesVector(request_data)
        line = request_data['line_num']
        column = request_data['column_num']

        fixits = getattr(self._completer, "GetFixItsForLocationInFile")(
            ToCppStringCompatible(filename), line, column, files, flags, True)

        # don't raise an error if not fixits: - leave that to the client to respond
        # in a nice way

        return responses.BuildFixItResponse(fixits)

    def OnFileReadyToParse(self, request_data):
        filename = request_data['filepath']
        if not filename:
            raise ValueError(INVALID_FILE_MESSAGE)

        flags = self._FlagsForRequest(request_data)
        if not flags:
            raise ValueError(NO_COMPILE_FLAGS_MESSAGE)

        with self._files_being_compiled.GetExclusive(filename):
            diagnostics = self._completer.UpdateTranslationUnit(
                ToCppStringCompatible(filename),
                self.GetUnsavedFilesVector(request_data), flags)

        diagnostics = _FilterDiagnostics(diagnostics)
        self._diagnostic_store = DiagnosticsToDiagStructure(diagnostics)
        return [
            responses.BuildDiagnosticData(x)
            for x in diagnostics[:self._max_diagnostics_to_display]
        ]

    def OnBufferUnload(self, request_data):
        self._completer.DeleteCachesForFile(
            ToCppStringCompatible(request_data['filepath']))

    def GetDetailedDiagnostic(self, request_data):
        current_line = request_data['line_num']
        current_column = request_data['column_num']
        current_file = request_data['filepath']

        if not self._diagnostic_store:
            raise ValueError(NO_DIAGNOSTIC_MESSAGE)

        diagnostics = self._diagnostic_store[current_file][current_line]
        if not diagnostics:
            raise ValueError(NO_DIAGNOSTIC_MESSAGE)

        closest_diagnostic = None
        distance_to_closest_diagnostic = 999

        # FIXME: all of these calculations are currently working with byte
        # offsets, which are technically incorrect. We should be working with
        # codepoint offsets, as we want the nearest character-wise diagnostic
        for diagnostic in diagnostics:
            distance = abs(current_column -
                           diagnostic.location_.column_number_)
            if distance < distance_to_closest_diagnostic:
                distance_to_closest_diagnostic = distance
                closest_diagnostic = diagnostic

        return responses.BuildDisplayMessageResponse(
            closest_diagnostic.long_formatted_text_)

    def DebugInfo(self, request_data):
        try:
            # Note that it only raises NoExtraConfDetected:
            #  - when extra_conf is None and,
            #  - there is no compilation database
            flags = self._FlagsForRequest(request_data) or []
        except (NoExtraConfDetected, UnknownExtraConf):
            # If _FlagsForRequest returns None or raises, we use an empty list in
            # practice.
            flags = []

        try:
            database_directory = self._flags.FindCompilationDatabase(
                os.path.dirname(request_data['filepath'])).database_directory
        except NoCompilationDatabase:
            database_directory = None

        database_item = responses.DebugInfoItem(
            key='compilation database path',
            value='{0}'.format(database_directory))
        flags_item = responses.DebugInfoItem(key='flags',
                                             value='{0}'.format(list(flags)))

        return responses.BuildDebugInfoResponse(
            name='C-family', items=[database_item, flags_item])

    def _FlagsForRequest(self, request_data):
        filename = request_data['filepath']
        if 'compilation_flags' in request_data:
            return PrepareFlagsForClang(request_data['compilation_flags'],
                                        filename)
        client_data = request_data.get('extra_conf_data', None)
        return self._flags.FlagsForFile(filename, client_data=client_data)