1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
#include "Scanner.hpp"
#include "CxxLexerAPI.h"
#include "CxxScannerTokens.h"
#include "CxxTokenizer.h"
#include "file_logger.h"
#include "fileutils.h"
Scanner::Scanner() {}
Scanner::~Scanner() {}
void Scanner::scan(const wxFileName& current_file, const wxArrayString& search_path, wxStringSet_t* includes_set,
wxStringSet_t* using_ns_set)
{
wxString content;
if(!FileUtils::ReadFileContent(current_file, content)) {
return;
}
scan_buffer(current_file, content, search_path, includes_set, using_ns_set);
}
void Scanner::scan_buffer(const wxFileName& current_file, const wxString& content, const wxArrayString& search_path,
wxStringSet_t* includes_set, wxStringSet_t* using_ns_set)
{
CxxTokenizer tokenizer;
wxString cur_file_dir = current_file.GetPath();
wxStringSet_t seen_includes;
tokenizer.Reset(content);
CxxLexerToken token;
while(tokenizer.NextToken(token)) {
switch(token.GetType()) {
case T_PP_INCLUDE_FILENAME: {
std::set<wxString> fixed_path;
wxString include_line = fix_include_line(token.GetWXString());
if(!include_line.empty() // valid include line
&& seen_includes.count(include_line) == 0 &&
IsFileExists(cur_file_dir, include_line, search_path, fixed_path)) {
seen_includes.insert(include_line);
for (const auto& path: fixed_path) {
includes_set->insert(path);
}
}
} break;
case T_USING:
ParseUsingNamespace(tokenizer, using_ns_set);
break;
default:
break;
}
}
}
#ifdef __WXMSW__
#define DIR_SEP "\\"
#else
#define DIR_SEP "/"
#endif
static wxString fix_separators_to_platform(const wxString& str)
{
wxString s = str;
#ifdef __WXMSW__
s.Replace("/", "\\");
#else
s.Replace("\\", "/");
#endif
return s;
}
bool Scanner::IsFileExists(const wxString& current_dir, const wxString& name, const wxArrayString& search_path,
std::set<wxString>& fixed_path)
{
if(m_missing_includes.count(name))
return false;
if(m_matches.count(name)) {
fixed_path = m_matches[name];
return true;
}
wxStructStat buf;
wxString fullpath = current_dir + DIR_SEP + name;
fullpath = fix_separators_to_platform(fullpath);
if(wxStat(fullpath, &buf) == 0) {
wxFileName fn(fullpath);
fn.MakeAbsolute();
fixed_path.insert(fn.GetFullPath());
}
// try the search paths
for(const wxString& path : search_path) {
fullpath = path + DIR_SEP + name;
fullpath = fix_separators_to_platform(fullpath);
if(wxStat(fullpath, &buf) == 0) {
fixed_path.insert(fullpath);
}
}
if (!fixed_path.empty()) {
m_matches.insert({ name, fixed_path });
return true;
}
m_missing_includes.insert(name);
return false;
}
void Scanner::ParseUsingNamespace(CxxTokenizer& tokenizer, wxStringSet_t* using_ns_set)
{
// Get the next token
CxxLexerToken token;
tokenizer.NextToken(token);
if(token.GetType() != T_NAMESPACE)
return;
// Read everything until we find the ';'
wxString usingNamespace;
while(tokenizer.NextToken(token)) {
if(token.GetType() == ';') {
break;
}
usingNamespace << token.GetText();
}
if(!usingNamespace.empty() && using_ns_set->count(usingNamespace) == 0) {
if(!usingNamespace.StartsWith("std::_") && !usingNamespace.Contains("GLIBCXX") && usingNamespace != "__pstl" &&
usingNamespace != "__detail") {
using_ns_set->insert(usingNamespace);
}
}
}
wxString Scanner::fix_include_line(const wxString& include_line)
{
// skip STL debug folders
if(include_line.StartsWith("<debug/")) {
return "";
}
wxString includeName = include_line;
includeName.Replace("\"", "");
includeName.Replace("<", "");
includeName.Replace(">", "");
return includeName;
}
|