//===-- SearchFilter.h ------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_SearchFilter_h_
#define liblldb_SearchFilter_h_

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/FileSpec.h"
#include "lldb/Core/Address.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Core/Module.h"

namespace lldb_private {

//----------------------------------------------------------------------
/// @class Searcher SearchFilter.h "lldb/Core/SearchFilter.h"
/// @brief Class that is driven by the SearchFilter to search the
/// SymbolContext space of the target program.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
/// General Outline:
/// Provides the callback and search depth for the SearchFilter search.
//----------------------------------------------------------------------

class Searcher
{
public:
    typedef enum {
        eCallbackReturnStop = 0,  // Stop the iteration
        eCallbackReturnContinue,  // Continue the iteration
        eCallbackReturnPop        // Pop one level up and continue iterating
    } CallbackReturn;

    typedef enum {
        eDepthTarget,
        eDepthModule,
        eDepthCompUnit,
        eDepthFunction,
        eDepthBlock,
        eDepthAddress
    } Depth;

    Searcher ();

    virtual ~Searcher ();

    virtual CallbackReturn
    SearchCallback (SearchFilter &filter,
                    SymbolContext &context,
                    Address *addr,
                    bool complete) = 0;

    virtual Depth
    GetDepth () = 0;

    //------------------------------------------------------------------
    /// Prints a canonical description for the searcher to the stream \a s.
    ///
    /// @param[in] s
    ///   Stream to which the output is copied.
    //------------------------------------------------------------------
    virtual void
    GetDescription(Stream *s);
};

//----------------------------------------------------------------------
/// @class SearchFilter SearchFilter.h "lldb/Core/SearchFilter.h"
/// @brief Class descends through the SymbolContext space of the target,
/// applying a filter at each stage till it reaches the depth specified by
/// the GetDepth method of the searcher, and calls its callback at that point.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
/// General Outline:
/// Provides the callback and search depth for the SearchFilter search.
///
/// The search is done by cooperation between the search filter and the searcher.
/// The search filter does the heavy work of recursing through the SymbolContext
/// space of the target program's symbol space.  The Searcher specifies the depth
/// at which it wants its callback to be invoked.  Note that since the resolution
/// of the Searcher may be greater than that of the SearchFilter, before the
/// Searcher qualifies an address it should pass it to "AddressPasses."
/// The default implementation is "Everything Passes."
//----------------------------------------------------------------------

class SearchFilter
{
public:

    //------------------------------------------------------------------
    /// The basic constructor takes a Target, which gives the space to search.
    ///
    /// @param[in] target
    ///    The Target that provides the module list to search.
    //------------------------------------------------------------------
    SearchFilter (lldb::TargetSP &target_sp);

    SearchFilter(const SearchFilter& rhs);

    virtual
    ~SearchFilter ();

    const SearchFilter&
    operator=(const SearchFilter& rhs);

    //------------------------------------------------------------------
    /// Call this method with a file spec to see if that spec passes the filter.
    ///
    /// @param[in] spec
    ///    The file spec to check against the filter.
    /// @return
    ///    \b true if \a spec passes, and \b false otherwise.
    //------------------------------------------------------------------
    virtual bool
    ModulePasses (const FileSpec &spec);

    //------------------------------------------------------------------
    /// Call this method with a Module to see if that module passes the filter.
    ///
    /// @param[in] module
    ///    The Module to check against the filter.
    ///
    /// @return
    ///    \b true if \a module passes, and \b false otherwise.
    //------------------------------------------------------------------
    virtual bool
    ModulePasses (const lldb::ModuleSP &module_sp);

    //------------------------------------------------------------------
    /// Call this method with a SymbolContext and a SymbolContextScope to see if
    /// that SymbolContext passes the filter up to the level in \a scope.
    ///
    /// @param[in] context
    ///    The SymbolContext to check against the filter.
    ///
    /// @param[in] scope
    ///    The SymbolContextItem indicating what bits of the SymbolContextScope
    ///    to check against the filter.
    ///
    ///  @return
    ///    \b true if \a SymbolContext passes, and \b false otherwise.
    //------------------------------------------------------------------
    virtual bool
    SymbolContextPasses (const SymbolContext &context,
                         lldb::SymbolContextItem scope);
    //------------------------------------------------------------------
    /// Call this method with a Address to see if \a address passes the filter.
    ///
    /// @param[in] addr
    ///    The address to check against the filter.
    ///
    /// @return
    ///    \b true if \a address passes, and \b false otherwise.
    //------------------------------------------------------------------
    virtual bool
    AddressPasses (Address &addr);

    //------------------------------------------------------------------
    /// Call this method with a FileSpec to see if \a file spec passes the filter
    /// as the name of a compilation unit.
    ///
    /// @param[in] fileSpec
    ///    The file spec to check against the filter.
    ///
    /// @return
    ///    \b true if \a file spec passes, and \b false otherwise.
    //------------------------------------------------------------------
    virtual bool
    CompUnitPasses (FileSpec &fileSpec);

    //------------------------------------------------------------------
    /// Call this method with a CompileUnit to see if \a comp unit passes the filter.
    ///
    /// @param[in] compUnit
    ///    The CompileUnit to check against the filter.
    ///
    /// @return
    ///    \b true if \a Comp Unit passes, and \b false otherwise.
    //------------------------------------------------------------------
    virtual bool
    CompUnitPasses (CompileUnit &compUnit);

    //------------------------------------------------------------------
    /// Call this method to do the search using the Searcher.
    ///
    /// @param[in] searcher
    ///    The searcher to drive with this search.
    ///
    //------------------------------------------------------------------
    virtual void
    Search (Searcher &searcher);

    //------------------------------------------------------------------
    /// Call this method to do the search using the Searcher in the module list
    /// \a modules.
    ///
    /// @param[in] searcher
    ///    The searcher to drive with this search.
    ///
    /// @param[in] modules
    ///    The module list within which to restrict the search.
    ///
    //------------------------------------------------------------------
    virtual void
    SearchInModuleList (Searcher &searcher, ModuleList &modules);

    //------------------------------------------------------------------
    /// Prints a canonical description for the search filter to the stream \a s.
    ///
    /// @param[in] s
    ///   Stream to which the output is copied.
    //------------------------------------------------------------------
    virtual void
    GetDescription(Stream *s);

    //------------------------------------------------------------------
    /// Standard "Dump" method.  At present it does nothing.
    //------------------------------------------------------------------
    virtual void
    Dump (Stream *s) const;

protected:

    // These are utility functions to assist with the search iteration.  They are used by the
    // default Search method.

    Searcher::CallbackReturn
    DoModuleIteration (const SymbolContext &context,
                       Searcher &searcher);

    Searcher::CallbackReturn
    DoModuleIteration (const lldb::ModuleSP& module_sp,
                       Searcher &searcher);

    Searcher::CallbackReturn
    DoCUIteration (const lldb::ModuleSP& module_sp,
                   const SymbolContext &context,
                   Searcher &searcher);

    Searcher::CallbackReturn
    DoFunctionIteration (Function *function,
                         const SymbolContext &context,
                         Searcher &searcher);

    lldb::TargetSP m_target_sp;   // Every filter has to be associated with a target for
                                  // now since you need a starting place for the search.
};

//----------------------------------------------------------------------
/// @class SearchFilterByModule SearchFilter.h "lldb/Core/SearchFilter.h"
/// @brief This is a SearchFilter that restricts the search to a given module.
//----------------------------------------------------------------------

class SearchFilterByModule :
    public SearchFilter
{
public:

    //------------------------------------------------------------------
    /// The basic constructor takes a Target, which gives the space to search,
    /// and the module to restrict the search to.
    ///
    /// @param[in] target
    ///    The Target that provides the module list to search.
    ///
    /// @param[in] module
    ///    The Module that limits the search.
    //------------------------------------------------------------------
    SearchFilterByModule (lldb::TargetSP &targetSP,
                          const FileSpec &module);

    SearchFilterByModule (const SearchFilterByModule& rhs);

    virtual
    ~SearchFilterByModule ();

    const SearchFilterByModule&
    operator=(const SearchFilterByModule& rhs);

    virtual bool
    ModulePasses (const lldb::ModuleSP &module_sp);

    virtual bool
    ModulePasses (const FileSpec &spec);

    virtual bool
    SymbolContextPasses (const SymbolContext &context,
                         lldb::SymbolContextItem scope);

    virtual bool
    AddressPasses (Address &address);

    virtual bool
    CompUnitPasses (FileSpec &fileSpec);

    virtual bool
    CompUnitPasses (CompileUnit &compUnit);

    virtual void
    GetDescription(Stream *s);

    virtual void
    Dump (Stream *s) const;

    virtual void
    Search (Searcher &searcher);

private:
    FileSpec m_module_spec;
};

} // namespace lldb_private

#endif  // liblldb_SearchFilter_h_
