Synopsis - Cross-Reference

File: /Synopsis/Parsers/Cxx/Filter.cc
  1//
  2// Copyright (C) 2002 Stephen Davies
  3// Copyright (C) 2002 Stefan Seefeld
  4// All rights reserved.
  5// Licensed to the public under the terms of the GNU LGPL (>= 2),
  6// see the file COPYING for details.
  7//
  8
  9#include <Synopsis/Python/Module.hh>
 10#include <Synopsis/Trace.hh>
 11#include <Support/Path.hh>
 12#include "Filter.hh"
 13#include <map>
 14#include <iostream>
 15#include <stdexcept>
 16
 17using namespace Synopsis;
 18
 19struct FileFilter::Private
 20{
 21
 22    //. used during SourceFile imports
 23    PyObject *asg;
 24
 25    //. Whether only main declarations should be stored
 26    bool only_main;
 27
 28    //. The main filename
 29    std::string main_filename;
 30
 31    //. The basename
 32    std::string base_path;
 33
 34    //. A vector of strings
 35    typedef std::vector<std::string> string_vector;
 36
 37    //. The sxr filename prefix
 38    std::string sxr_prefix;
 39
 40    //. Type of the map from filename to SourceFile
 41    typedef std::map<std::string, ASG::SourceFile*> file_map_t;
 42
 43    //. A map from filename to SourceFile
 44    file_map_t file_map;
 45};
 46
 47namespace
 48{
 49    //. The FileFilter instance
 50    FileFilter* filter_instance = 0;
 51
 52//. restore the relevant parts from the python asg
 53//. The returned SourceFile object is a slice of the original python object
 54//. and should be merged back at the end of the parsing such that the other
 55//. parts not mirrored here are preserved.
 56ASG::SourceFile *import_source_file(PyObject *ir,
 57				    const std::string &name,
 58				    const std::string &abs_name,
 59				    bool primary)
 60{
 61  ASG::SourceFile *sourcefile = new ASG::SourceFile(name, abs_name, primary);
 62
 63  PyObject *files = PyObject_GetAttrString(ir, "files");
 64  assert(files);
 65  PyObject *py_source_file = PyDict_GetItemString(files, const_cast<char *>(name.c_str()));
 66  Py_DECREF(files);
 67  if (!py_source_file) return sourcefile; // the given file wasn't preprocessed into the ASG
 68
 69  PyObject *macro_calls = PyObject_GetAttrString(py_source_file, "macro_calls");
 70  long size = PyObject_Length(macro_calls);
 71  for (long i = 0; i != size; ++i)
 72  {
 73    PyObject *call = PyList_GetItem(macro_calls, i);
 74    PyObject *call_name = PyObject_GetAttrString(call, "name");
 75    PyObject *end = PyObject_GetAttrString(call, "end");
 76    PyObject *expanded_start = PyObject_GetAttrString(call, "expanded_start");
 77    PyObject *expanded_end = PyObject_GetAttrString(call, "expanded_end");
 78    char const *macro_name = PyString_AsString(call_name);
 79    int col = PyInt_AsLong(PyTuple_GetItem(end, 1));
 80    int start_line = PyInt_AsLong(PyTuple_GetItem(expanded_start, 0));
 81    int start_col = PyInt_AsLong(PyTuple_GetItem(expanded_start, 1));
 82    int end_line = PyInt_AsLong(PyTuple_GetItem(expanded_end, 0));
 83    int end_col = PyInt_AsLong(PyTuple_GetItem(expanded_end, 1));
 84    if (start_line == end_line)
 85      sourcefile->add_macro_call(macro_name,
 86                                 start_line, start_col, end_col, end_col - col);
 87    else
 88    {
 89      // first line
 90      sourcefile->add_macro_call(macro_name, start_line, start_col, -1, 0);
 91      for (int line = start_line + 1; line != end_line; ++line)
 92        sourcefile->add_macro_call(macro_name, line, 0, -1, 0);
 93      // last line
 94      sourcefile->add_macro_call(macro_name, end_line, 0, end_col, end_col - col);
 95    }
 96    Py_DECREF(expanded_end);
 97    Py_DECREF(expanded_start);
 98    Py_DECREF(end);
 99    Py_DECREF(call_name);
100  }
101  Py_DECREF(macro_calls);
102  return sourcefile;
103}
104}
105
106// Constructor
107FileFilter::FileFilter(PyObject *asg,
108		       const std::string &filename,
109		       const std::string &base_path,
110		       bool main)
111{
112    m = new Private;
113    m->asg = asg;
114    m->main_filename = filename;
115    m->base_path = base_path;
116    m->only_main = main;
117    filter_instance = this;
118}
119
120// Destructor
121FileFilter::~FileFilter()
122{
123    delete m;
124    filter_instance = 0;
125}
126
127// Return instance pointer
128FileFilter* FileFilter::instance()
129{
130    return filter_instance;
131}
132
133// Sets the prefix for sxr output filenames.
134void FileFilter::set_sxr_prefix(const char* filename)
135{
136    m->sxr_prefix = filename;
137    if (m->sxr_prefix.size() > 0
138        && m->sxr_prefix[m->sxr_prefix.size()-1] != '/')
139       m->sxr_prefix.append("/");
140}
141
142// Returns the ASG::SourceFile for the given filename.
143ASG::SourceFile* FileFilter::get_sourcefile(const char* filename_ptr, size_t length)
144{
145    std::string filename;
146    if (length != 0)
147        filename.assign(filename_ptr, length);
148    else
149        filename.assign(filename_ptr);
150    
151    Path path = Path(filename).abs();
152    std::string abs_filename = path.str();
153    path.strip(m->base_path);
154    filename = path.str();
155    // Look in map
156    Private::file_map_t::iterator iter = m->file_map.find(abs_filename);
157    if (iter != m->file_map.end())
158        // Found
159        return iter->second;
160    
161    // Not found, create a new SourceFile. Note filename in the object is
162    // stripped of the basename
163    ASG::SourceFile* file = import_source_file(m->asg,
164					       filename,
165					       abs_filename, 
166					       is_main(abs_filename));
167
168    // Add to the map
169    m->file_map[abs_filename] = file;
170
171    return file;
172}
173
174bool FileFilter::is_main(std::string filename)
175{
176    if (filename == m->main_filename) return true;
177    else if (m->only_main) return false;
178
179    if (m->base_path.size() == 0) return true;
180
181    size_t length = m->base_path.size();
182    if (length > filename.size()) return false;
183    return strncmp(filename.data(), m->base_path.data(), length) == 0;
184}
185
186// Returns whether a function implementation in the given file should
187// have it's Ptree walked. This will be true only if the given file is
188// one of the files to be stored. 
189bool FileFilter::should_visit_function_impl(ASG::SourceFile* file)
190{
191  // First check if not linking or xreffing
192  if (m->sxr_prefix.empty())
193    return false;
194
195  return file->is_primary();
196}
197
198
199// Returns true if links should be generated for the given sourcefile
200bool FileFilter::should_xref(ASG::SourceFile* file)
201{
202  return !m->sxr_prefix.empty() && file->is_primary();
203}
204
205// Returns true if the given declaration should be stored in the final
206// ASG.
207bool FileFilter::should_store(ASG::Declaration* decl)
208{
209    // Sanity check (this can happen)
210    if (!decl)
211        return false;
212    // Check the decl itself first, although for namespaces the SourceFile
213    // referenced by file() can be any of the files that opened it
214    if (decl->file()->is_primary())
215        return true;
216    if (ASG::Scope* scope = dynamic_cast<ASG::Scope*>(decl))
217    {
218        // Check all members of the namespace or class
219        ASG::Declaration::vector::iterator iter;
220        ASG::Declaration::vector& declarations = scope->declarations();
221        for (iter = declarations.begin(); iter != declarations.end(); iter++)
222            if (should_store(*iter))
223                // Only takes one to store the decl. Each contained declaration
224                // will then be evaluated separately
225                return true;
226    }
227
228    return false;
229}
230
231// Strip base path from filename
232std::string FileFilter::strip_base_path(const std::string& filename)
233{
234    if (m->base_path.size() == 0)
235        return filename;
236    size_t length = m->base_path.size();
237    if (length > filename.size())
238        return filename;
239    if (strncmp(filename.data(), m->base_path.data(), length) == 0)
240        return filename.substr(length);
241    return filename;
242}
243
244// Return syntax filename
245std::string FileFilter::get_sxr_filename(ASG::SourceFile* file)
246{
247    return m->sxr_prefix + file->name() + ".sxr";
248}
249
250// Returns all sourcefiles
251void FileFilter::get_all_sourcefiles(ASG::SourceFile::vector& all)
252{
253    Private::file_map_t::iterator iter;
254    for (iter = m->file_map.begin(); iter != m->file_map.end(); iter++)
255        all.push_back(iter->second);
256}
257
258std::string FileFilter::get_main_file()
259{
260  return m->main_filename;
261}