/* * This file is part of Code::Blocks Studio, an open-source cross-platform IDE * Copyright (C) 2003 Yiannis An. Mandravellos * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact e-mail: Yiannis An. Mandravellos * Program URL : http://www.codeblocks.org * * $Id: parser.cpp,v 1.25.2.1 2005/10/25 07:59:01 mandrav Exp $ * $Date: 2005/10/25 07:59:01 $ */ #include #include #include #include #include #include #include #include "parser.h" #ifndef STANDALONE #include #include #include #include #endif // STANDALONE static const char CACHE_MAGIC[] = "CCCACHE_1_0"; static char CACHE_MAGIC_READ[] = " "; static wxMutex s_mutexListProtection; int PARSER_END = wxNewId(); static int idPool = wxNewId(); BEGIN_EVENT_TABLE(Parser, wxEvtHandler) // EVT_MENU(NEW_TOKEN, Parser::OnNewToken) // EVT_MENU(FILE_NEEDS_PARSING, Parser::OnParseFile) EVT_THREADTASK_STARTED(idPool, Parser::OnStartThread) EVT_THREADTASK_ENDED(idPool, Parser::OnEndThread) EVT_THREADTASK_ALLDONE(idPool, Parser::OnAllThreadsDone) END_EVENT_TABLE() Parser::Parser(wxEvtHandler* parent) : m_MaxThreadsCount(8), m_pParent(parent) #ifndef STANDALONE ,m_pImageList(0L) #endif ,m_abort_flag(false), m_UsingCache(false), m_CacheFilesCount(0), m_CacheTokensCount(0), m_Pool(this, idPool) { ReadOptions(); #ifndef STANDALONE m_pImageList = new wxImageList(16, 16); wxBitmap bmp; wxString prefix; prefix = ConfigManager::Get()->Read(_T("data_path")) + _T("/images/codecompletion/"); // bitmaps must be added by order of PARSER_IMG_* consts bmp.LoadFile(prefix + _T("class_folder.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_CLASS_FOLDER bmp.LoadFile(prefix + _T("class.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_CLASS bmp.LoadFile(prefix + _T("ctor_private.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_CTOR_PRIVATE bmp.LoadFile(prefix + _T("ctor_protected.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_CTOR_PROTECTED bmp.LoadFile(prefix + _T("ctor_public.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_CTOR_PUBLIC bmp.LoadFile(prefix + _T("dtor_private.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_DTOR_PRIVATE bmp.LoadFile(prefix + _T("dtor_protected.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_DTOR_PROTECTED bmp.LoadFile(prefix + _T("dtor_public.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_DTOR_PUBLIC bmp.LoadFile(prefix + _T("method_private.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_FUNC_PRIVATE bmp.LoadFile(prefix + _T("method_protected.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_FUNC_PRIVATE bmp.LoadFile(prefix + _T("method_public.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_FUNC_PUBLIC bmp.LoadFile(prefix + _T("var_private.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_VAR_PRIVATE bmp.LoadFile(prefix + _T("var_protected.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_VAR_PROTECTED bmp.LoadFile(prefix + _T("var_public.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_VAR_PUBLIC bmp.LoadFile(prefix + _T("preproc.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_PREPROCESSOR bmp.LoadFile(prefix + _T("enum.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_ENUM bmp.LoadFile(prefix + _T("enumerator.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_ENUMERATOR bmp.LoadFile(prefix + _T("namespace.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_NAMESPACE bmp.LoadFile(prefix + _T("symbols_folder.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_SYMBOLS_FOLDER bmp.LoadFile(prefix + _T("enums_folder.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_ENUMS_FOLDER bmp.LoadFile(prefix + _T("preproc_folder.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_PREPROC_FOLDER bmp.LoadFile(prefix + _T("others_folder.png"), wxBITMAP_TYPE_PNG); m_pImageList->Add(bmp); // PARSER_IMG_OTHERS_FOLDER #endif // STANDALONE ConnectEvents(); } Parser::~Parser() { DisconnectEvents(); Clear(); #ifndef STANDALONE delete m_pImageList; #endif // STANDALONE } void Parser::ConnectEvents() { // Connect(EVT_THREADTASK_STARTED, -1, cbEVT_THREADTASK_STARTED, // (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction) // &Parser::OnStartThread); // Connect(EVT_THREADTASK_ENDED, -1, cbEVT_THREADTASK_ENDED, // (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction) // &Parser::OnEndThread); Connect(NEW_TOKEN, -1, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction) &Parser::OnNewToken); Connect(FILE_NEEDS_PARSING, -1, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction) &Parser::OnParseFile); } void Parser::DisconnectEvents() { // Disconnect(EVT_THREADTASK_STARTED, -1, cbEVT_THREADTASK_STARTED);//, // Disconnect(EVT_THREADTASK_ENDED, -1, cbEVT_THREADTASK_ENDED);//, Disconnect(NEW_TOKEN, -1, wxEVT_COMMAND_MENU_SELECTED);//, Disconnect(FILE_NEEDS_PARSING, -1, wxEVT_COMMAND_MENU_SELECTED);//, } void Parser::ReadOptions() { #ifdef STANDALONE m_Options.followLocalIncludes = true; m_Options.followGlobalIncludes = false; m_Options.caseSensitive = true; m_Options.wantPreprocessor = false; m_Options.useSmartSense = true; m_BrowserOptions.showInheritance = false; m_BrowserOptions.viewFlat = false; #else // !STANDALONE m_MaxThreadsCount = ConfigManager::Get()->Read(_T("/code_completion/max_threads"), 8); m_Options.followLocalIncludes = ConfigManager::Get()->Read(_T("/code_completion/parser_follow_local_includes"), 1L); m_Options.followGlobalIncludes = ConfigManager::Get()->Read(_T("/code_completion/parser_follow_global_includes"), 0L); m_Options.caseSensitive = ConfigManager::Get()->Read(_T("/code_completion/case_sensitive"), 0L); m_Options.useSmartSense = ConfigManager::Get()->Read(_T("/code_completion/use_SmartSense"), 1); m_Options.wantPreprocessor = ConfigManager::Get()->Read(_T("/code_completion/want_preprocessor"), 0L); m_BrowserOptions.showInheritance = ConfigManager::Get()->Read(_T("/code_completion/browser_show_inheritance"), 0L); m_BrowserOptions.viewFlat = ConfigManager::Get()->Read(_T("/code_completion/browser_view_flat"), 0L); #endif // STANDALONE } void Parser::WriteOptions() { #ifndef STANDALONE ConfigManager::Get()->Write(_T("/code_completion/max_threads"), (int)m_MaxThreadsCount); ConfigManager::Get()->Write(_T("/code_completion/parser_follow_local_includes"), m_Options.followLocalIncludes); ConfigManager::Get()->Write(_T("/code_completion/parser_follow_global_includes"), m_Options.followGlobalIncludes); ConfigManager::Get()->Write(_T("/code_completion/case_sensitive"), m_Options.caseSensitive); ConfigManager::Get()->Write(_T("/code_completion/use_SmartSense"), m_Options.useSmartSense); ConfigManager::Get()->Write(_T("/code_completion/want_preprocessor"), m_Options.wantPreprocessor); ConfigManager::Get()->Write(_T("/code_completion/browser_show_inheritance"), m_BrowserOptions.showInheritance); ConfigManager::Get()->Write(_T("/code_completion/browser_view_flat"), m_BrowserOptions.viewFlat); #endif // STANDALONE } bool Parser::CacheNeedsUpdate() { if (m_UsingCache) { ClearTemporaries(); // no temps in counting if (m_CacheFilesCount == (int)m_ParsedFiles.GetCount() && m_CacheTokensCount == (int)m_Tokens.GetCount()) { // in-mem data and cache seem to be in sync // @warning: this is *not* bulletproof! // consider a token name change, for example... // maybe use a CRC of some kind? return false; } } return true; } bool Parser::ReadFromCache(wxFile* f) { // File format is like this: // // CACHE_MAGIC // Number of parsed files // Number of tokens // Parsed files // Tokens // EOF // keep a backup of include dirs wxArrayString dirs = m_IncludeDirs; Manager::Get()->GetMessageManager()->DebugLog(_("Clearing Cache")); Clear(); // restore backup m_IncludeDirs = dirs; Manager::Get()->GetMessageManager()->DebugLog(_("Begin reading...")); if (f->Read(CACHE_MAGIC_READ, sizeof(CACHE_MAGIC_READ)) != sizeof(CACHE_MAGIC_READ) || strncmp(CACHE_MAGIC, CACHE_MAGIC_READ, sizeof(CACHE_MAGIC_READ) != 0)) { return false; } int fcount = 0; int tcount = 0; Manager::Get()->GetMessageManager()->DebugLog(_("Reading fcount...")); if (!LoadIntFromFile(f, &fcount)) return false; Manager::Get()->GetMessageManager()->DebugLog(_("Reading tcount...")); if (!LoadIntFromFile(f, &tcount)) return false; wxProgressDialog* progress = 0; unsigned int counter = 0; // display cache progress? if (ConfigManager::Get()->Read(_T("/code_completion/show_cache_progress"), 1L)) { Manager::Get()->GetMessageManager()->DebugLog(_("Creating progress dialog...")); progress = new wxProgressDialog(_("Code-completion plugin"), _("Please wait while loading code-completion cache..."), fcount + tcount); } // m_ParsedFiles Manager::Get()->GetMessageManager()->DebugLog(_("Reading data from cache NOW")); wxString file; for (int i = 0; i < fcount && !f->Eof(); ++i) { if (!LoadStringFromFile(f, file)) { delete progress; return false; } m_ParsedFiles.Add(file); if (progress) progress->Update(++counter); } Manager::Get()->GetMessageManager()->DebugLog(_("Calculating tokens...")); // m_Tokens for (int i = 0; i < tcount && !f->Eof(); ++i) { // update m_Int for inheritance to be serialized properly Token* token = new Token; token->m_Int = i; m_Tokens.Add(token); } for (int i = 0; i < tcount && !f->Eof(); ++i) { Token* token = m_Tokens[i]; if (!token->SerializeIn(f)) { delete progress; return false; } if (progress) progress->Update(++counter); } Manager::Get()->GetMessageManager()->DebugLog(_("Updating linking pointers...")); // now we must update linking pointers in tokens for (int i = 0; i < tcount; ++i) { Token* token = m_Tokens[i]; token->m_pParent = token->m_ParentIndex != -1 ? m_Tokens[token->m_ParentIndex] : 0; // sanity check if (token->m_pParent == token) token->m_pParent = 0; for (unsigned int j = 0; j < token->m_AncestorsIndices.GetCount(); ++j) { if (token->m_AncestorsIndices[j] != -1) { Token* ancestor = m_Tokens[token->m_AncestorsIndices[j]]; if (ancestor != token) // sanity check token->m_Ancestors.Add(ancestor); } } for (unsigned int j = 0; j < token->m_ChildrenIndices.GetCount(); ++j) { if (token->m_ChildrenIndices[j] != -1) { Token* child = m_Tokens[token->m_ChildrenIndices[j]]; if (child != token) // sanity check token->m_Children.Add(child); } } } // LinkInheritance(); // fix ancestors relationships Manager::Get()->GetMessageManager()->DebugLog(_("Cleaning up subroutine...")); m_UsingCache = true; m_CacheFilesCount = m_ParsedFiles.GetCount(); m_CacheTokensCount = m_Tokens.GetCount(); Manager::Get()->GetMessageManager()->DebugLog(_("Deleting progress dialog (if any)...")); if (progress) delete progress; Manager::Get()->GetMessageManager()->DebugLog(_("Finished reading from cache.")); return true; } bool Parser::WriteToCache(wxFile* f) { // File format is like this: // // CACHE_MAGIC // Number of parsed files // Number of tokens // Parsed files // Tokens // EOF ClearTemporaries(); // no temps in cache unsigned int tcount = m_Tokens.GetCount(); unsigned int fcount = m_ParsedFiles.GetCount(); unsigned int counter = 0; wxProgressDialog* progress = 0; // display cache progress? if (ConfigManager::Get()->Read(_T("/code_completion/show_cache_progress"), 1L)) { progress = new wxProgressDialog(_("Code-completion plugin"), _("Please wait while saving code-completion cache..."), tcount + fcount); } // write cache magic f->Write(CACHE_MAGIC, sizeof(CACHE_MAGIC)); SaveIntToFile(f, fcount); // num parsed files SaveIntToFile(f, tcount); // num tokens // m_ParsedFiles for (unsigned int i = 0; i < fcount; ++i) { SaveStringToFile(f, m_ParsedFiles[i]); if (progress) progress->Update(++counter); } // m_Tokens for (unsigned int i = 0; i < tcount; ++i) { // update m_Int for inheritance to be serialized properly Token* token = m_Tokens[i]; token->m_Int = i; } for (unsigned int i = 0; i < tcount; ++i) { Token* token = m_Tokens[i]; token->SerializeOut(f); if (progress) progress->Update(++counter); } if (progress) delete progress; return true; } unsigned int Parser::GetFilesCount() { wxMutexLocker lock(s_mutexListProtection); return m_ParsedFiles.GetCount(); } bool Parser::Done() { wxMutexLocker lock(s_mutexListProtection); return m_Pool.Done(); } #ifndef STANDALONE void Parser::SetTokenKindImage(int kind, const wxBitmap& bitmap, const wxBitmap& mask) { if (kind < PARSER_IMG_MIN || kind > PARSER_IMG_MAX) return; #ifdef __WXMSW__ m_pImageList->Replace(kind, bitmap, mask); #endif } void Parser::SetTokenKindImage(int kind, const wxBitmap& bitmap, const wxColour& maskColor) { if (kind < PARSER_IMG_MIN || kind > PARSER_IMG_MAX) return; m_pImageList->Replace(kind, bitmap);//, maskColor); } void Parser::SetTokenKindImage(int kind, const wxIcon& icon) { if (kind < PARSER_IMG_MIN || kind > PARSER_IMG_MAX) return; m_pImageList->Replace(kind, icon); } int Parser::GetTokenKindImage(Token* token) { if (!token) return PARSER_IMG_NONE; switch (token->m_TokenKind) { case tkPreprocessor: return PARSER_IMG_PREPROCESSOR; case tkEnum: return PARSER_IMG_ENUM; case tkEnumerator: return PARSER_IMG_ENUMERATOR; case tkClass: return PARSER_IMG_CLASS; case tkNamespace: return PARSER_IMG_NAMESPACE; case tkConstructor: switch (token->m_Scope) { case tsProtected: return PARSER_IMG_CTOR_PROTECTED; case tsPrivate: return PARSER_IMG_CTOR_PRIVATE; default: return PARSER_IMG_CTOR_PUBLIC; } case tkDestructor: switch (token->m_Scope) { case tsProtected: return PARSER_IMG_DTOR_PROTECTED; case tsPrivate: return PARSER_IMG_DTOR_PRIVATE; default: return PARSER_IMG_DTOR_PUBLIC; } case tkFunction: switch (token->m_Scope) { case tsProtected: return PARSER_IMG_FUNC_PROTECTED; case tsPrivate: return PARSER_IMG_FUNC_PRIVATE; default: return PARSER_IMG_FUNC_PUBLIC; } case tkVariable: switch (token->m_Scope) { case tsProtected: return PARSER_IMG_VAR_PROTECTED; case tsPrivate: return PARSER_IMG_VAR_PRIVATE; default: return PARSER_IMG_VAR_PUBLIC; } default: return PARSER_IMG_NONE; } } #endif // STANDALONE Token* Parser::FindTokenByName(const wxString& name, bool globalsOnly, short int kindMask) { // for (unsigned int i = m_Tokens.GetCount() - 1; i >= 0; --i) Token* res = 0; for (unsigned int i = 0; i < m_Tokens.GetCount(); ++i) { Token* token = m_Tokens[i]; if (globalsOnly && token->m_pParent) continue; if ((token->m_TokenKind & kindMask) && token->m_Name.Matches(name)) { res = token; // Manager::Get()->GetMessageManager()->DebugLog("token=%s (%d)", name.c_str(), token->m_Children.GetCount()); // return token; } } // return 0; return res; } Token* Parser::FindChildTokenByName(Token* parent, const wxString& name, bool useInheritance, short int kindMask) { if (!parent) return FindTokenByName(name, false, kindMask); for (unsigned int i = 0; i < parent->m_Children.GetCount(); ++i) { Token* token = parent->m_Children[i]; if ((token->m_TokenKind & kindMask) && token->m_Name.Matches(name)) return token; } // not found; check ancestors now... if (useInheritance) { for (unsigned int i = 0; i < parent->m_Ancestors.GetCount(); ++i) { Token* inherited = FindChildTokenByName(parent->m_Ancestors[i], name, true, kindMask); if (inherited) return inherited; } } return 0L; } Token* Parser::FindTokenByDisplayName(const wxString& name) { for (unsigned int i = 0; i < m_Tokens.GetCount(); ++i) { Token* token = m_Tokens[i]; if (token->m_DisplayName.Matches(name)) return token; } return 0L; } int TokensSortProc(Token** first, Token** second) { Token* parent1 = first[0]->m_pParent; Token* parent2 = second[0]->m_pParent; int diff = 0; if (first[0]->m_IsTemporary != second[0]->m_IsTemporary) { // local block token, always first in list return first[0]->m_IsTemporary ? -1 : 1; } else if (first[0]->m_IsLocal != second[0]->m_IsLocal) { // project tokens first, then global return first[0]->m_IsLocal ? -1 : 1; } else if (parent1 && !parent2) { // first tokens that have a parent return -1; } else if (!parent1 && parent2) { // first tokens that have a parent return 1; } else if (parent1 && parent2) { if (parent1 != parent2) { // if both tokens have parent, order by *parent* name diff = parent1->m_Name.CompareTo(parent2->m_Name); if (diff) return diff; } } // order by token kind int ret = first[0]->m_TokenKind - second[0]->m_TokenKind; // finally order by token name, if all else fails... if (!ret) ret = first[0]->m_Name.CompareTo(second[0]->m_Name); return ret; } void Parser::SortAllTokens() { m_Tokens.Sort(TokensSortProc); } void Parser::LinkInheritance(bool tempsOnly) { //Manager::Get()->GetMessageManager()->DebugLog("Linking inheritance..."); for (unsigned int i = 0; i < m_Tokens.GetCount(); ++i) { Token* token = m_Tokens[i]; if (token->m_TokenKind != tkClass) continue; if (tempsOnly && !token->m_IsTemporary) continue; if (token->m_AncestorsString.IsEmpty()) continue; // only local symbols might change inheritance if (token->m_IsLocal) { //Manager::Get()->GetMessageManager()->DebugLog("Removing ancestors from %s", token->m_Name.c_str()); token->m_Ancestors.Clear(); } else continue; //Manager::Get()->GetMessageManager()->DebugLog("Token %s, Ancestors %s", token->m_Name.c_str(), token->m_AncestorsString.c_str()); wxStringTokenizer tkz(token->m_AncestorsString, _T(",")); while (tkz.HasMoreTokens()) { wxString ancestor = tkz.GetNextToken(); if (ancestor.IsEmpty() || ancestor == token->m_Name) continue; //Manager::Get()->GetMessageManager()->DebugLog("Ancestor %s", ancestor.c_str()); Token* ancestorToken = FindTokenByName(ancestor, tkClass); //Manager::Get()->GetMessageManager()->DebugLog(ancestorToken ? "Found" : "not Found"); if (ancestorToken) { //Manager::Get()->GetMessageManager()->DebugLog("Adding ancestor %s to %s", ancestorToken->m_Name.c_str(), token->m_Name.c_str()); token->m_Ancestors.Add(ancestorToken); } } if (!token->m_IsLocal) // global symbols are linked once { //Manager::Get()->GetMessageManager()->DebugLog("Removing ancestor string from %s", token->m_Name.c_str(), token->m_Name.c_str()); token->m_AncestorsString.Clear(); } } } bool Parser::ParseBuffer(const wxString& buffer, bool isLocal, bool bufferSkipBlocks) { ParserThreadOptions opts; opts.wantPreprocessor = m_Options.wantPreprocessor; opts.useBuffer = true; opts.bufferSkipBlocks = bufferSkipBlocks; return Parse(buffer, isLocal, opts); } void Parser::BatchParse(const wxArrayString& filenames) { m_Pool.BatchBegin(); for (unsigned int i = 0; i < filenames.GetCount(); ++i) Parse(filenames[i]); m_Pool.BatchEnd(); } bool Parser::Parse(const wxString& filename, bool isLocal) { ParserThreadOptions opts; opts.wantPreprocessor = m_Options.wantPreprocessor; opts.useBuffer = false; opts.bufferSkipBlocks = false; return Parse(UnixFilename(filename), isLocal, opts); } bool Parser::Parse(const wxString& bufferOrFilename, bool isLocal, ParserThreadOptions& opts) { wxString buffOrFile = bufferOrFilename; wxMutexLocker* lock = new wxMutexLocker(s_mutexListProtection); bool parsed = !opts.useBuffer && m_ParsedFiles.Index(buffOrFile) != wxNOT_FOUND; delete lock; if (parsed) { #ifndef STANDALONE // Manager::Get()->GetMessageManager()->DebugLog("%s is already parsed", buffOrFile.c_str()); #endif return false; // already parsed } ParserThread* thread = new ParserThread(this,&this->m_abort_flag, buffOrFile, isLocal, opts, &m_Tokens); if (!opts.useBuffer) { // lock = new wxMutexLocker(s_mutexListProtection); m_ParsedFiles.Add(buffOrFile); // LOGSTREAM << "Adding task for: " << buffOrFile << '\n'; m_Pool.AddTask(thread, true); // delete lock; return true; } else { bool ret = thread->Parse(); LinkInheritance(true); delete thread; return ret; } } bool Parser::ParseBufferForFunctions(const wxString& buffer) { ParserThreadOptions opts; opts.wantPreprocessor = m_Options.wantPreprocessor; opts.useBuffer = false; opts.bufferSkipBlocks = false; ParserThread* thread = new ParserThread(this,&this->m_abort_flag, wxEmptyString, false, opts, &m_Tokens); return thread->ParseBufferForFunctions(buffer); } bool Parser::RemoveFile(const wxString& filename) { wxMutexLocker lock(s_mutexListProtection); wxMutexLocker lock1(s_mutexProtection); wxString file = UnixFilename(filename); if (m_ParsedFiles.Index(file) != wxNOT_FOUND) { // only if it has been parsed before... // delete any entries that belong to the file in question // FIXME: what happens with entries *linked* to this entry? unsigned int i = 0; while (i < m_Tokens.GetCount()) { if (m_Tokens[i]->m_Filename.Matches(file)) m_Tokens.RemoveAt(i); else ++i; } m_ParsedFiles.Remove(file); } else return false; return true; } bool Parser::Reparse(const wxString& filename, bool isLocal) { if (!Done()) return false; // if still parsing, exit with error wxString file = UnixFilename(filename); // Manager::Get()->GetMessageManager()->DebugLog(_("Reparsing %s"), file.c_str()); RemoveFile(file); ClearTemporaries(); wxMutexLocker* lock = new wxMutexLocker(s_mutexListProtection); m_ReparsedFiles.Add(file); delete lock; return Parse(file, isLocal); } void Parser::Clear() { // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Disconnecting events...")); DisconnectEvents(); // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Terminating all threads...")); TerminateAllThreads(); wxSafeYield(); wxSleep(0); wxMutexLocker* lockl = new wxMutexLocker(s_mutexListProtection); // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Clearing 'm_ParsedFiles'...")); m_ParsedFiles.Clear(); // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Clearing 'm_ReparsedFiles'...")); m_ReparsedFiles.Clear(); // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Clearing 'm_IncludeDirs'...")); m_IncludeDirs.Clear(); delete lockl; // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Locking s_mutexProtection and clearing m_Tokens...")); wxMutexLocker lock(s_mutexProtection); WX_CLEAR_ARRAY(m_Tokens); m_Tokens.Clear(); // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: wxSafeYield...")); wxSafeYield(); // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Connecting Events...")); ConnectEvents(); m_UsingCache = false; m_CacheFilesCount = 0; m_CacheTokensCount = 0; m_abort_flag = false; // Manager::Get()->GetMessageManager()->DebugLog(_("Parser::Clear: Done.")); } void Parser::ClearTemporaries() { if (!Done()) return; unsigned int i = 0; while (i < m_Tokens.GetCount()) { Token* token = m_Tokens[i]; if (token->m_IsTemporary) m_Tokens.RemoveAt(i); else ++i; } } void Parser::TerminateAllThreads() { Manager::Get()->GetMessageManager()->DebugLog(_("Parser::TerminateAllThreads: Aborting all tasks...")); m_Pool.AbortAllTasks(); } void Parser::PauseAllThreads() { // wxLogNull ln; // no other logging // wxMutexLocker lock(s_mutexListProtection); // for (unsigned int i = 0; i < m_Threads.GetCount(); ++i) // m_Threads[i]->Pause(); } void Parser::ResumeAllThreads() { // wxLogNull ln; // no other logging // wxMutexLocker lock(s_mutexListProtection); // for (unsigned int i = 0; i < m_Threads.GetCount(); ++i) // m_Threads[i]->Resume(); } void Parser::OnStartThread(CodeBlocksEvent& event) { event.Skip(); } void Parser::OnEndThread(CodeBlocksEvent& event) { event.Skip(); } void Parser::OnAllThreadsDone(CodeBlocksEvent& event) { LinkInheritance(false); wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, PARSER_END); evt.SetClientData(this); wxPostEvent(m_pParent, evt); } void Parser::OnNewToken(wxCommandEvent& event) { #ifndef STANDALONE Manager::Get()->GetMessageManager()->DebugLog(event.GetString()); #endif } void Parser::OnParseFile(wxCommandEvent& event) { // LOGSTREAM << "Parser::OnParseFile: " << event.GetString() << "\n"; // a ParserThread ran into an #include directive // it's up to us to decide to parse this file... if ((event.GetInt() == 0 && !m_Options.followLocalIncludes) || (event.GetInt() == 1 && !m_Options.followGlobalIncludes)) return; // the string is thread's_filename+included_filename wxString filename = event.GetString(); int idx = filename.First('+'); wxFileName fname; wxFileName source; wxString base; if (idx == -1) return; fname.Assign(filename.Mid(idx + 1)); source.Assign(filename.Left(idx - 1)); if (event.GetInt() == 0) base = source.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR); else { // loop through all known include dirs // and locate the file... for (unsigned int i = 0; i < m_IncludeDirs.GetCount(); ++i) { base = m_IncludeDirs[i]; wxFileName tmp = fname; tmp.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, base); if (wxFileExists(tmp.GetFullPath())) break; } } fname.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, base); filename = fname.GetFullPath(); /*wxMutexLocker* lock = new wxMutexLocker(s_mutexListProtection); bool abort = m_ReparsedFiles.Index(filename) != wxNOT_FOUND; delete lock; if (abort) return; // the file is being re-parsed; don't follow includes */ if (m_ParsedFiles.Index(filename) != wxNOT_FOUND) // parsed file return; // Manager::Get()->GetMessageManager()->DebugLog("Adding in parse queue: %s", filename.c_str()); bool res = false; if (m_ReparsedFiles.Index(source.GetFullPath()) != wxNOT_FOUND) // reparsing file res = Reparse(filename, event.GetInt() == 0); else res = Parse(filename, event.GetInt() == 0); if (res) { #if 0 #ifndef STANDALONE Manager::Get()->GetMessageManager()->DebugLog("Adding in parse queue: %s", filename.c_str()); #endif #endif } } void Parser::BuildTree(wxTreeCtrl& tree) { if (!Done()) return; tree.Freeze(); tree.DeleteAllItems(); #ifndef STANDALONE tree.SetImageList(m_pImageList); #endif m_RootNode = tree.AddRoot(_("Symbols"), PARSER_IMG_SYMBOLS_FOLDER); if (m_BrowserOptions.viewFlat) { for (unsigned int x = 0; x < m_Tokens.GetCount(); ++x) { Token* token = m_Tokens[x]; if (!token->m_pParent && // base (no parent) token->m_IsLocal) // local symbols only AddTreeNode(tree, m_RootNode, token); } tree.Expand(m_RootNode); tree.Thaw(); return; } wxTreeItemId globalNS = tree.AppendItem(m_RootNode, _("Global namespace"), PARSER_IMG_NAMESPACE); AddTreeNamespace(tree, globalNS, 0L); BuildTreeNamespace(tree, m_RootNode, 0L); tree.Expand(m_RootNode); tree.Thaw(); } void Parser::BuildTreeNamespace(wxTreeCtrl& tree, const wxTreeItemId& parentNode, Token* parent) { for (unsigned int x = 0; x < m_Tokens.GetCount(); ++x) { Token* token = m_Tokens[x]; if (token->m_pParent == parent && token->m_IsLocal && // local symbols only token->m_TokenKind == tkNamespace) // namespaces { ClassTreeData* ctd = new ClassTreeData(token); wxTreeItemId newNS = tree.AppendItem(parentNode, token->m_Name, PARSER_IMG_NAMESPACE, -1, ctd); BuildTreeNamespace(tree, newNS, token); AddTreeNamespace(tree, newNS, token); } } } void Parser::AddTreeNamespace(wxTreeCtrl& tree, const wxTreeItemId& parentNode, Token* parent) { wxTreeItemId node = tree.AppendItem(parentNode, _("Classes"), PARSER_IMG_CLASS_FOLDER); for (unsigned int x = 0; x < m_Tokens.GetCount(); ++x) { Token* token = m_Tokens[x]; if (token->m_pParent == parent && // parent matches token->m_IsLocal && // local symbols only token->m_TokenKind == tkClass) // classes { AddTreeNode(tree, node, token); } } node = tree.AppendItem(parentNode, _("Enums"), PARSER_IMG_ENUMS_FOLDER); for (unsigned int x = 0; x < m_Tokens.GetCount(); ++x) { Token* token = m_Tokens[x]; if (token->m_pParent == parent && // parent matches token->m_IsLocal && // local symbols only token->m_TokenKind == tkEnum) // enums { AddTreeNode(tree, node, token); } } node = tree.AppendItem(parentNode, _("Preprocessor"), PARSER_IMG_PREPROC_FOLDER); for (unsigned int x = 0; x < m_Tokens.GetCount(); ++x) { Token* token = m_Tokens[x]; if (token->m_pParent == parent && // parent matches token->m_IsLocal && // local symbols only token->m_TokenKind == tkPreprocessor) // preprocessor { AddTreeNode(tree, node, token); } } node = tree.AppendItem(parentNode, _("Others"), PARSER_IMG_OTHERS_FOLDER); for (unsigned int x = 0; x < m_Tokens.GetCount(); ++x) { Token* token = m_Tokens[x]; if (token->m_pParent == parent && // parent matches token->m_IsLocal && // local symbols only (token->m_TokenKind == tkEnumerator || // enumerators token->m_TokenKind == tkFunction || // functions token->m_TokenKind == tkVariable || // variables token->m_TokenKind == tkUndefined)) // others { AddTreeNode(tree, node, token); } } } void Parser::AddTreeNode(wxTreeCtrl& tree, const wxTreeItemId& parentNode, Token* token, bool childrenOnly) { if (!token) return; ClassTreeData* ctd = new ClassTreeData(token); int image = -1; #ifndef STANDALONE image = GetTokenKindImage(token); #endif wxString str = token->m_Name + token->m_Args; if (!token->m_ActualType.IsEmpty()) str = str + _T(" : ") + token->m_ActualType; wxTreeItemId node = childrenOnly ? parentNode : tree.AppendItem(parentNode, str, image, -1, ctd); // add children for (unsigned int i = 0; i < token->m_Children.GetCount(); ++i) { Token* childToken = token->m_Children[i]; AddTreeNode(tree, node, childToken); } if (!m_BrowserOptions.showInheritance || (token->m_TokenKind != tkClass && token->m_TokenKind != tkNamespace)) return; // add ancestor's children for (unsigned int x = 0; x < token->m_Ancestors.GetCount(); ++x) { Token* ancestor = token->m_Ancestors[x]; AddTreeNode(tree, node, ancestor, true); } }