Synopsis - Cross-Reference
File: /Synopsis/Parsers/Cxx/Filter.cc1// 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}