Code::Blocks  SVN r11506
nativeparser.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  *
5  * $Revision: 11399 $
6  * $Id: nativeparser.cpp 11399 2018-05-08 21:54:03Z fuscated $
7  * $HeadURL: https://svn.code.sf.net/p/codeblocks/code/trunk/src/plugins/codecompletion/nativeparser.cpp $
8  */
9 
10 #include <sdk.h>
11 
12 #ifndef CB_PRECOMP
13  #include <cctype>
14 
15  #include <wx/dir.h>
16  #include <wx/log.h> // for wxSafeShowMessage()
17  #include <wx/regex.h>
18  #include <wx/wfstream.h>
19 
20  #include <cbauibook.h>
21  #include <cbeditor.h>
22  #include <cbexception.h>
23  #include <cbproject.h>
24  #include <compilerfactory.h>
25  #include <configmanager.h>
26  #include <editormanager.h>
27  #include <logmanager.h>
28  #include <macrosmanager.h>
29  #include <manager.h>
30  #include <pluginmanager.h>
31  #include <prep.h> // nullptr
32  #include <projectmanager.h>
33 
34  #include <tinyxml/tinyxml.h>
35 #endif
36 
37 #include <wx/tokenzr.h>
38 
39 #include <cbstyledtextctrl.h>
41 #include <projectloader_hooks.h>
42 #include <tinyxml.h>
43 
44 #include "nativeparser.h"
45 #include "classbrowser.h"
46 #include "parser/parser.h"
47 #include "parser/profiletimer.h"
48 
49 #define CC_NATIVEPARSER_DEBUG_OUTPUT 0
50 
51 #if defined (CC_GLOBAL_DEBUG_OUTPUT)
52  #if CC_GLOBAL_DEBUG_OUTPUT == 1
53  #undef CC_NATIVEPARSER_DEBUG_OUTPUT
54  #define CC_NATIVEPARSER_DEBUG_OUTPUT 1
55  #elif CC_GLOBAL_DEBUG_OUTPUT == 2
56  #undef CC_NATIVEPARSER_DEBUG_OUTPUT
57  #define CC_NATIVEPARSER_DEBUG_OUTPUT 2
58  #endif
59 #endif
60 
61 #if CC_NATIVEPARSER_DEBUG_OUTPUT == 1
62  #define TRACE(format, args...) \
63  CCLogger::Get()->DebugLog(F(format, ##args))
64  #define TRACE2(format, args...)
65 #elif CC_NATIVEPARSER_DEBUG_OUTPUT == 2
66  #define TRACE(format, args...) \
67  do \
68  { \
69  if (g_EnableDebugTrace) \
70  CCLogger::Get()->DebugLog(F(format, ##args)); \
71  } \
72  while (false)
73  #define TRACE2(format, args...) \
74  CCLogger::Get()->DebugLog(F(format, ##args))
75 #else
76  #define TRACE(format, args...)
77  #define TRACE2(format, args...)
78 #endif
79 
80 /*
81  * (Recursive) functions that are surrounded by a critical section:
82  * GenerateResultSet() -> AddChildrenOfUnnamed
83  * GetCallTips() -> PrettyPrintToken (recursive function)
84  * FindCurrentFunctionToken() -> ParseFunctionArguments, FindAIMatches (recursive function)
85  * GenerateResultSet (recursive function):
86  * FindAIMatches(), ResolveActualType(), ResolveExpression(),
87  * FindCurrentFunctionToken(), ResolveOperator()
88  * FindCurrentFunctionStart() -> GetTokenFromCurrentLine
89  */
90 
92 {
94  {
95  public:
96  ParserDirTraverser(const wxString& excludePath, wxArrayString& files) :
97  m_ExcludeDir(excludePath),
98  m_Files(files)
99  {}
100 
101  wxDirTraverseResult OnFile(const wxString& filename) override
102  {
104  m_Files.Add(filename);
105  return wxDIR_CONTINUE;
106  }
107 
108  wxDirTraverseResult OnDir(const wxString& dirname) override
109  {
110  if (dirname == m_ExcludeDir)
111  return wxDIR_IGNORE;
112  if (m_Files.GetCount() == 1)
113  return wxDIR_STOP;
114  m_Files.Clear();
115  return wxDIR_CONTINUE;
116  }
117 
118  private:
121  };
122 }// namespace NativeParserHelper
123 
126 
128 bool s_DebugSmartSense = false;
129 
131  m_TimerParsingOneByOne(this, idTimerParsingOneByOne),
132  m_ClassBrowser(nullptr),
133  m_ClassBrowserIsFloating(false),
134  m_ImageList(nullptr),
135  m_ParserPerWorkspace(false),
136  m_LastAISearchWasGlobal(false),
137  m_LastControl(nullptr),
138  m_LastFunctionIndex(-1),
139  m_LastFuncTokenIdx(-1),
140  m_LastLine(-1),
141  m_LastResult(-1)
142 {
143  m_TempParser = new Parser(this, nullptr);
145 
146  m_ImageList = new wxImageList(16, 16);
147  wxBitmap bmp;
148  wxString prefix;
149  prefix = ConfigManager::GetDataFolder() + _T("/images/codecompletion/");
150  // bitmaps must be added by order of PARSER_IMG_* consts
151  bmp = cbLoadBitmap(prefix + _T("class_folder.png"), wxBITMAP_TYPE_PNG);
152  m_ImageList->Add(bmp); // PARSER_IMG_CLASS_FOLDER
153  bmp = cbLoadBitmap(prefix + _T("class.png"), wxBITMAP_TYPE_PNG);
154  m_ImageList->Add(bmp); // PARSER_IMG_CLASS
155  bmp = cbLoadBitmap(prefix + _T("class_private.png"), wxBITMAP_TYPE_PNG);
156  m_ImageList->Add(bmp); // PARSER_IMG_CLASS_PRIVATE
157  bmp = cbLoadBitmap(prefix + _T("class_protected.png"), wxBITMAP_TYPE_PNG);
158  m_ImageList->Add(bmp); // PARSER_IMG_CLASS_PROTECTED
159  bmp = cbLoadBitmap(prefix + _T("class_public.png"), wxBITMAP_TYPE_PNG);
160  m_ImageList->Add(bmp); // PARSER_IMG_CLASS_PUBLIC
161  bmp = cbLoadBitmap(prefix + _T("ctor_private.png"), wxBITMAP_TYPE_PNG);
162  m_ImageList->Add(bmp); // PARSER_IMG_CTOR_PRIVATE
163  bmp = cbLoadBitmap(prefix + _T("ctor_protected.png"), wxBITMAP_TYPE_PNG);
164  m_ImageList->Add(bmp); // PARSER_IMG_CTOR_PROTECTED
165  bmp = cbLoadBitmap(prefix + _T("ctor_public.png"), wxBITMAP_TYPE_PNG);
166  m_ImageList->Add(bmp); // PARSER_IMG_CTOR_PUBLIC
167  bmp = cbLoadBitmap(prefix + _T("dtor_private.png"), wxBITMAP_TYPE_PNG);
168  m_ImageList->Add(bmp); // PARSER_IMG_DTOR_PRIVATE
169  bmp = cbLoadBitmap(prefix + _T("dtor_protected.png"), wxBITMAP_TYPE_PNG);
170  m_ImageList->Add(bmp); // PARSER_IMG_DTOR_PROTECTED
171  bmp = cbLoadBitmap(prefix + _T("dtor_public.png"), wxBITMAP_TYPE_PNG);
172  m_ImageList->Add(bmp); // PARSER_IMG_DTOR_PUBLIC
173  bmp = cbLoadBitmap(prefix + _T("method_private.png"), wxBITMAP_TYPE_PNG);
174  m_ImageList->Add(bmp); // PARSER_IMG_FUNC_PRIVATE
175  bmp = cbLoadBitmap(prefix + _T("method_protected.png"), wxBITMAP_TYPE_PNG);
176  m_ImageList->Add(bmp); // PARSER_IMG_FUNC_PRIVATE
177  bmp = cbLoadBitmap(prefix + _T("method_public.png"), wxBITMAP_TYPE_PNG);
178  m_ImageList->Add(bmp); // PARSER_IMG_FUNC_PUBLIC
179  bmp = cbLoadBitmap(prefix + _T("var_private.png"), wxBITMAP_TYPE_PNG);
180  m_ImageList->Add(bmp); // PARSER_IMG_VAR_PRIVATE
181  bmp = cbLoadBitmap(prefix + _T("var_protected.png"), wxBITMAP_TYPE_PNG);
182  m_ImageList->Add(bmp); // PARSER_IMG_VAR_PROTECTED
183  bmp = cbLoadBitmap(prefix + _T("var_public.png"), wxBITMAP_TYPE_PNG);
184  m_ImageList->Add(bmp); // PARSER_IMG_VAR_PUBLIC
185  bmp = cbLoadBitmap(prefix + _T("macro_def.png"), wxBITMAP_TYPE_PNG);
186  m_ImageList->Add(bmp); // PARSER_IMG_MACRO_DEF
187  bmp = cbLoadBitmap(prefix + _T("enum.png"), wxBITMAP_TYPE_PNG);
188  m_ImageList->Add(bmp); // PARSER_IMG_ENUM
189  bmp = cbLoadBitmap(prefix + _T("enum_private.png"), wxBITMAP_TYPE_PNG);
190  m_ImageList->Add(bmp); // PARSER_IMG_ENUM_PRIVATE
191  bmp = cbLoadBitmap(prefix + _T("enum_protected.png"), wxBITMAP_TYPE_PNG);
192  m_ImageList->Add(bmp); // PARSER_IMG_ENUM_PROTECTED
193  bmp = cbLoadBitmap(prefix + _T("enum_public.png"), wxBITMAP_TYPE_PNG);
194  m_ImageList->Add(bmp); // PARSER_IMG_ENUM_PUBLIC
195  bmp = cbLoadBitmap(prefix + _T("enumerator.png"), wxBITMAP_TYPE_PNG);
196  m_ImageList->Add(bmp); // PARSER_IMG_ENUMERATOR
197  bmp = cbLoadBitmap(prefix + _T("namespace.png"), wxBITMAP_TYPE_PNG);
198  m_ImageList->Add(bmp); // PARSER_IMG_NAMESPACE
199  bmp = cbLoadBitmap(prefix + _T("typedef.png"), wxBITMAP_TYPE_PNG);
200  m_ImageList->Add(bmp); // PARSER_IMG_TYPEDEF
201  bmp = cbLoadBitmap(prefix + _T("typedef_private.png"), wxBITMAP_TYPE_PNG);
202  m_ImageList->Add(bmp); // PARSER_IMG_TYPEDEF_PRIVATE
203  bmp = cbLoadBitmap(prefix + _T("typedef_protected.png"), wxBITMAP_TYPE_PNG);
204  m_ImageList->Add(bmp); // PARSER_IMG_TYPEDEF_PROTECTED
205  bmp = cbLoadBitmap(prefix + _T("typedef_public.png"), wxBITMAP_TYPE_PNG);
206  m_ImageList->Add(bmp); // PARSER_IMG_TYPEDEF_PUBLIC
207  bmp = cbLoadBitmap(prefix + _T("symbols_folder.png"), wxBITMAP_TYPE_PNG);
208  m_ImageList->Add(bmp); // PARSER_IMG_SYMBOLS_FOLDER
209  bmp = cbLoadBitmap(prefix + _T("vars_folder.png"), wxBITMAP_TYPE_PNG);
210  m_ImageList->Add(bmp); // PARSER_IMG_VARS_FOLDER
211  bmp = cbLoadBitmap(prefix + _T("funcs_folder.png"), wxBITMAP_TYPE_PNG);
212  m_ImageList->Add(bmp); // PARSER_IMG_FUNCS_FOLDER
213  bmp = cbLoadBitmap(prefix + _T("enums_folder.png"), wxBITMAP_TYPE_PNG);
214  m_ImageList->Add(bmp); // PARSER_IMG_ENUMS_FOLDER
215  bmp = cbLoadBitmap(prefix + _T("macro_def_folder.png"), wxBITMAP_TYPE_PNG);
216  m_ImageList->Add(bmp); // PARSER_IMG_MACRO_DEF_FOLDER
217  bmp = cbLoadBitmap(prefix + _T("others_folder.png"), wxBITMAP_TYPE_PNG);
218  m_ImageList->Add(bmp); // PARSER_IMG_OTHERS_FOLDER
219  bmp = cbLoadBitmap(prefix + _T("typedefs_folder.png"), wxBITMAP_TYPE_PNG);
220  m_ImageList->Add(bmp); // PARSER_IMG_TYPEDEF_FOLDER
221  bmp = cbLoadBitmap(prefix + _T("macro_use.png"), wxBITMAP_TYPE_PNG);
222  m_ImageList->Add(bmp); // PARSER_IMG_MACRO_USE
223  bmp = cbLoadBitmap(prefix + _T("macro_use_private.png"), wxBITMAP_TYPE_PNG);
224  m_ImageList->Add(bmp); // PARSER_IMG_MACRO_USE_PRIVATE
225  bmp = cbLoadBitmap(prefix + _T("macro_use_protected.png"), wxBITMAP_TYPE_PNG);
226  m_ImageList->Add(bmp); // PARSER_IMG_MACRO_USE_PROTECTED
227  bmp = cbLoadBitmap(prefix + _T("macro_use_public.png"), wxBITMAP_TYPE_PNG);
228  m_ImageList->Add(bmp); // PARSER_IMG_MACRO_USE_PUBLIC
229  bmp = cbLoadBitmap(prefix + _T("macro_use_folder.png"), wxBITMAP_TYPE_PNG);
230  m_ImageList->Add(bmp); // PARSER_IMG_MACRO_USE_FOLDER
231 
232  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
233  m_ParserPerWorkspace = cfg->ReadBool(_T("/parser_per_workspace"), false);
234 
235  // hook to project loading procedure
238 
239  Connect(ParserCommon::idParserStart, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(NativeParser::OnParserStart));
240  Connect(ParserCommon::idParserEnd, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(NativeParser::OnParserEnd));
242 }
243 
245 {
246  Disconnect(ParserCommon::idParserStart, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(NativeParser::OnParserStart));
247  Disconnect(ParserCommon::idParserEnd, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(NativeParser::OnParserEnd));
251  ClearParsers();
254 }
255 
257 {
259  {
260  std::set<cbProject*>::iterator it = m_ParsedProjects.find(project);
261  if (it != m_ParsedProjects.end())
262  return m_ParserList.begin()->second;
263  }
264  else
265  {
266  for (ParserList::const_iterator it = m_ParserList.begin(); it != m_ParserList.end(); ++it)
267  {
268  if (it->first == project)
269  return it->second;
270  }
271  }
272 
273  TRACE(_T("NativeParser::GetParserByProject(): Returning nullptr."));
274  return nullptr;
275 }
276 
278 {
279  cbProject* project = GetProjectByFilename(filename);
280  return GetParserByProject(project);
281 }
282 
284 {
285  for (ParserList::const_iterator it = m_ParserList.begin(); it != m_ParserList.end(); ++it)
286  {
287  if (it->second == parser)
288  return it->first;
289  }
290 
291  TRACE(_T("NativeParser::GetProjectByParser(): Returning NULL."));
292  return NULL;
293 }
294 
296 {
297  TRACE(_T("NativeParser::GetProjectByFilename(): %s"), filename.wx_str());
298  cbProject* activeProject = Manager::Get()->GetProjectManager()->GetActiveProject();
299  if (activeProject)
300  {
301  ParserBase* parser = GetParserByProject(activeProject);
302  if ( ( parser
303  && parser->IsFileParsed(filename) )
304  || activeProject->GetFileByFilename(filename, false, true) )
305  {
306  return activeProject;
307  }
308  else
309  {
310  ProjectsArray* projs = Manager::Get()->GetProjectManager()->GetProjects();
311  for (size_t i = 0; i < projs->GetCount(); ++i)
312  {
313  cbProject* project = projs->Item(i);
314  if (!project || project == activeProject)
315  continue;
316 
317  parser = GetParserByProject(project);
318  if ( ( parser
319  && parser->IsFileParsed(filename) )
320  || project->GetFileByFilename(filename, false, true) )
321  {
322  return project;
323  }
324  }
325  }
326  }
327 
328  return nullptr;
329 }
330 
332 {
333  if (!editor)
334  return nullptr;
335  ProjectFile* pf = editor->GetProjectFile();
336  if (pf && pf->GetParentProject())
337  return pf->GetParentProject();
338  return GetProjectByFilename(editor->GetFilename());
339 }
340 
342 {
344  cbProject* project = GetProjectByEditor(editor);
345  if (!project)
347  return project;
348 }
349 
351 {
352  bool done = true;
353  for (ParserList::const_iterator it = m_ParserList.begin(); it != m_ParserList.end(); ++it)
354  {
355  if (!it->second->Done())
356  {
357  done = false;
358  break;
359  }
360  }
361  TRACE(_T("NativeParser::Done(): %s"), done ? _T("true"): _T("false"));
362  return done;
363 }
364 
366 {
367  if (!token)
368  return PARSER_IMG_NONE;
369 
370  switch (token->m_TokenKind)
371  {
372  case tkMacroDef: return PARSER_IMG_MACRO_DEF;
373 
374  case tkEnum:
375  switch (token->m_Scope)
376  {
377  case tsPublic: return PARSER_IMG_ENUM_PUBLIC;
379  case tsPrivate: return PARSER_IMG_ENUM_PRIVATE;
380  case tsUndefined:
381  default: return PARSER_IMG_ENUM;
382  }
383 
384  case tkEnumerator: return PARSER_IMG_ENUMERATOR;
385 
386  case tkClass:
387  switch (token->m_Scope)
388  {
389  case tsPublic: return PARSER_IMG_CLASS_PUBLIC;
391  case tsPrivate: return PARSER_IMG_CLASS_PRIVATE;
392  case tsUndefined:
393  default: return PARSER_IMG_CLASS;
394  }
395 
396  case tkNamespace: return PARSER_IMG_NAMESPACE;
397 
398  case tkTypedef:
399  switch (token->m_Scope)
400  {
401  case tsPublic: return PARSER_IMG_TYPEDEF_PUBLIC;
404  case tsUndefined:
405  default: return PARSER_IMG_TYPEDEF;
406  }
407 
408  case tkMacroUse:
409  switch (token->m_Scope)
410  {
414  case tsUndefined:
415  default: return PARSER_IMG_MACRO_USE;
416  }
417 
418  case tkConstructor:
419  switch (token->m_Scope)
420  {
422  case tsPrivate: return PARSER_IMG_CTOR_PRIVATE;
423  case tsUndefined:
424  case tsPublic:
425  default: return PARSER_IMG_CTOR_PUBLIC;
426  }
427 
428  case tkDestructor:
429  switch (token->m_Scope)
430  {
432  case tsPrivate: return PARSER_IMG_DTOR_PRIVATE;
433  case tsUndefined:
434  case tsPublic:
435  default: return PARSER_IMG_DTOR_PUBLIC;
436  }
437 
438  case tkFunction:
439  switch (token->m_Scope)
440  {
442  case tsPrivate: return PARSER_IMG_FUNC_PRIVATE;
443  case tsUndefined:
444  case tsPublic:
445  default: return PARSER_IMG_FUNC_PUBLIC;
446  }
447 
448  case tkVariable:
449  switch (token->m_Scope)
450  {
452  case tsPrivate: return PARSER_IMG_VAR_PRIVATE;
453  case tsUndefined:
454  case tsPublic:
455  default: return PARSER_IMG_VAR_PUBLIC;
456  }
457 
458  case tkAnyContainer:
459  case tkAnyFunction:
460  case tkUndefined:
461  default: return PARSER_IMG_NONE;
462  }
463 }
464 
466 {
467  TRACE(_T("NativeParser::GetAllPathsByFilename(): Enter"));
468 
469  wxArrayString dirs;
470  const wxFileName fn(filename);
471 
472  wxDir dir(fn.GetPath());
473  if (!dir.IsOpened())
474  return wxArrayString();
475 
476  wxArrayString files;
478  const wxString filespec = fn.HasExt() ? fn.GetName() + _T(".*") : fn.GetName();
479  CCLogger::Get()->DebugLog(_T("NativeParser::GetAllPathsByFilename(): Traversing '") + fn.GetPath() + _T("' for: ") + filespec);
480 
481  dir.Traverse(traverser, filespec, wxDIR_FILES);
482 
483  // only find one file in the dir, go other place
484  if (files.GetCount() == 1)
485  {
488  // search in the project
489  if (project)
490  {
491  const wxString prjPath = project->GetCommonTopLevelPath();
492  wxString priorityPath;
493  if (fn.HasExt() && (fn.GetExt().StartsWith(_T("h")) || fn.GetExt().StartsWith(_T("c"))))
494  {
495  wxFileName priFn(prjPath);
496  // hard-coded candidate path, the ./sdk or ./include under the project top level folder
497  priFn.AppendDir(fn.GetExt().StartsWith(_T("h")) ? _T("sdk") : _T("include"));
498  if (priFn.DirExists())
499  {
500  priorityPath = priFn.GetFullPath();
501  wxDir priorityDir(priorityPath);
502  if ( priorityDir.IsOpened() )
503  {
504  wxArrayString priorityPathSub;
505  NativeParserHelper::ParserDirTraverser traverser_2(wxEmptyString, priorityPathSub);
506  CCLogger::Get()->DebugLog(_T("NativeParser::GetAllPathsByFilename(): Traversing '") + priorityPath + _T("' for: ") + filespec);
507  priorityDir.Traverse(traverser_2, filespec, wxDIR_FILES | wxDIR_DIRS);
508  if (priorityPathSub.GetCount() == 1)
509  AddPaths(dirs, priorityPathSub[0], fn.HasExt());
510  }
511  }
512  }
513 
514  if (dirs.IsEmpty())
515  {
516  wxDir prjDir(prjPath);
517  if (prjDir.IsOpened())
518  {
519  // try to search the project top level folder
520  wxArrayString prjDirSub;
521  NativeParserHelper::ParserDirTraverser traverser_2(priorityPath, prjDirSub);
522  CCLogger::Get()->DebugLog(_T("NativeParser::GetAllPathsByFilename(): Traversing '") + priorityPath + wxT(" - ") + prjPath + _T("' for: ") + filespec);
523  prjDir.Traverse(traverser_2, filespec, wxDIR_FILES | wxDIR_DIRS);
524  if (prjDirSub.GetCount() == 1)
525  AddPaths(dirs, prjDirSub[0], fn.HasExt());
526  }
527  }
528  }
529  }
530 
531  CCLogger::Get()->DebugLog(F(_T("NativeParser::GetAllPathsByFilename(): Found %lu files:"), static_cast<unsigned long>(files.GetCount())));
532  for (size_t i=0; i<files.GetCount(); i++)
533  CCLogger::Get()->DebugLog(F(_T("- %s"), files[i].wx_str()));
534 
535  if (!files.IsEmpty())
536  AddPaths(dirs, files[0], fn.HasExt());
537 
538  TRACE(_T("NativeParser::GetAllPathsByFilename(): Leave"));
539  return dirs;
540 }
541 
542 void NativeParser::AddPaths(wxArrayString& dirs, const wxString& path, bool hasExt)
543 {
544  wxString s;
545  if (hasExt)
546  s = UnixFilename(path.BeforeLast(_T('.'))) + _T(".");
547  else
548  s = UnixFilename(path);
549 
550  if (dirs.Index(s, false) == wxNOT_FOUND)
551  dirs.Add(s);
552 }
553 
555 {
556  if ( GetParserByProject(project) )
557  {
558  CCLogger::Get()->DebugLog(_T("NativeParser::CreateParser(): Parser for this project already exists!"));
559  return nullptr;
560  }
561 
562  // Easy case for "one parser per workspace" that has already been created:
563  if (m_ParserPerWorkspace && !m_ParsedProjects.empty())
564  return m_ParserList.begin()->second;
565 
566  TRACE(_T("NativeParser::CreateParser(): Calling DoFullParsing()"));
567 
568  ParserBase* parser = new Parser(this, project);
569  if ( !DoFullParsing(project, parser) )
570  {
571  CCLogger::Get()->DebugLog(_T("NativeParser::CreateParser(): Full parsing failed!"));
572  delete parser;
573  return nullptr;
574  }
575 
576  if (m_Parser == m_TempParser)
577  SetParser(parser); // Also updates class browser
578 
580  m_ParsedProjects.insert(project);
581 
582  m_ParserList.push_back(std::make_pair(project, parser));
583 
584  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
585  wxString log(F(_("NativeParser::CreateParser(): Finish creating a new parser for project '%s'"), prj.wx_str()));
586  CCLogger::Get()->Log(log);
587  CCLogger::Get()->DebugLog(log);
588 
590 
591  return parser;
592 }
593 
595 {
596  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
597 
598  ParserList::iterator it = m_ParserList.begin();
600  {
601  for (; it != m_ParserList.end(); ++it)
602  {
603  if (it->first == project)
604  break;
605  }
606  }
607 
608  if (it == m_ParserList.end())
609  {
610  CCLogger::Get()->DebugLog(F(_T("NativeParser::DeleteParser(): Parser does not exist for delete '%s'!"), prj.wx_str()));
611  return false;
612  }
613 
614  bool removeProjectFromParser = false;
616  removeProjectFromParser = RemoveProjectFromParser(project);
617 
618  if (m_ParsedProjects.empty()) // this indicates we are in one parser per one project mode
619  {
620  wxString log(F(_("NativeParser::DeleteParser(): Deleting parser for project '%s'!"), prj.wx_str()));
621  CCLogger::Get()->Log(log);
622  CCLogger::Get()->DebugLog(log);
623 
624  // the logic here is : firstly delete the parser instance, then see whether we need an
625  // active parser switch (call SetParser())
626  delete it->second;
627 
628  // if the active parser is deleted, set the active parser to nullptr
629  if (it->second == m_Parser)
630  {
631  m_Parser = nullptr;
632  SetParser(m_TempParser); // Also updates class browser
633  }
634 
635  m_ParserList.erase(it);
636 
637  return true;
638  }
639 
640  if (removeProjectFromParser)
641  return true;
642 
643  CCLogger::Get()->DebugLog(_T("NativeParser::DeleteParser(): Deleting parser failed!"));
644  return false;
645 }
646 
647 bool NativeParser::ReparseFile(cbProject* project, const wxString& filename)
648 {
650  return false;
651 
652  ParserBase* parser = GetParserByProject(project);
653  if (!parser)
654  return false;
655 
656  if (!parser->UpdateParsingProject(project))
657  return false;
658 
659  TRACE(_T("NativeParser::ReparseFile(): Calling Parser::Reparse()"));
660 
661  return parser->Reparse(filename);
662 }
663 
664 bool NativeParser::AddFileToParser(cbProject* project, const wxString& filename, ParserBase* parser)
665 {
667  return false;
668 
669  if (!parser)
670  {
671  parser = GetParserByProject(project);
672  if (!parser)
673  return false;
674  }
675 
676  if (!parser->UpdateParsingProject(project))
677  return false;
678 
679  TRACE(_T("NativeParser::AddFileToParser(): Calling Parser::AddFile()"));
680 
681  return parser->AddFile(filename, project);
682 }
683 
685 {
686  ParserBase* parser = GetParserByProject(project);
687  if (!parser)
688  return false;
689 
690  TRACE(_T("NativeParser::RemoveFileFromParser(): Calling Parser::RemoveFile()"));
691 
692  return parser->RemoveFile(filename);
693 }
694 
696 {
697  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
698 #if wxCHECK_VERSION(3, 0, 0)
699  bool useSymbolBrowser = false;
700 #else
701  bool useSymbolBrowser = cfg->ReadBool(_T("/use_symbols_browser"), true);
702 #endif // wxCHECK_VERSION
703 
704  if (useSymbolBrowser)
705  {
706  if (!m_ClassBrowser)
707  {
710  }
711  // change class-browser docking settings
712  else if (m_ClassBrowserIsFloating != cfg->ReadBool(_T("/as_floating_window"), false))
713  {
716  // force re-update
718  }
719  }
720  else if (!useSymbolBrowser && m_ClassBrowser)
722 
723  const bool parserPerWorkspace = cfg->ReadBool(_T("/parser_per_workspace"), false);
724  if (m_Parser == m_TempParser)
725  {
726  m_ParserPerWorkspace = parserPerWorkspace;
727  return;
728  }
729 
731 
732  // re-parse if settings changed
733  ParserOptions opts = m_Parser->Options();
735  bool reparse = false;
736  cbProject* project = GetCurrentProject();
742  || m_ParserPerWorkspace != parserPerWorkspace )
743  {
744  // important options changed... flag for reparsing
745  if (cbMessageBox(_("You changed some class parser options. Do you want to "
746  "reparse your projects now, using the new options?"),
747  _("Reparse?"), wxYES_NO | wxICON_QUESTION) == wxID_YES)
748  {
749  reparse = true;
750  }
751  }
752 
753  if (reparse)
754  ClearParsers();
755 
756  m_ParserPerWorkspace = parserPerWorkspace;
757 
758  if (reparse)
759  CreateParser(project);
760 }
761 
763 {
764  cbProject* project = GetCurrentProject();
765  if (project)
766  {
767  TRACE(_T("NativeParser::ReparseCurrentProject(): Calling DeleteParser() and CreateParser()"));
768  DeleteParser(project);
769  CreateParser(project);
770  }
771 }
772 
774 {
776  if (!tree)
777  return;
778 
780  if (!treeItem.IsOk())
781  return;
782 
783  const FileTreeData* data = static_cast<FileTreeData*>(tree->GetItemData(treeItem));
784  if (!data)
785  return;
786 
787  if (data->GetKind() == FileTreeData::ftdkProject)
788  {
789  cbProject* project = data->GetProject();
790  if (project)
791  {
792  TRACE(_T("NativeParser::ReparseSelectedProject(): Calling DeleteParser() and CreateParser()"));
793  DeleteParser(project);
794  CreateParser(project);
795  }
796  }
797 }
798 
799 // Here, we collect the "using namespace XXXX" directives
800 // Also, we locate the current caret in which function, then, add the function parameters to Token trie
801 // Also, the variables in the function body( local block ) was add to the Token trie
803  TokenIdxSet& result,
804  bool reallyUseAI,
805  bool isPrefix,
806  bool caseSensitive,
807  int caretPos)
808 {
809  result.clear();
810 
811  if (!m_Parser->Done())
812  {
813  wxString msg(_("The Parser is still parsing files."));
814  msg += m_Parser->NotDoneReason();
815  CCLogger::Get()->DebugLog(msg);
816  return 0;
817  }
818 
819  TRACE(_T("NativeParser::MarkItemsByAI_2()"));
820 
822 
824 
825  // remove old temporaries
826  tree->Clear();
827 
829 
831 
832  // find "using namespace" directives in the file
833  TokenIdxSet search_scope;
834  ParseUsingNamespace(searchData, search_scope, caretPos);
835 
836  // parse function's arguments
837  ParseFunctionArguments(searchData, caretPos);
838 
839  // parse current code block (from the start of function up to the cursor)
840  ParseLocalBlock(searchData, search_scope, caretPos);
841 
842  if (!reallyUseAI)
843  {
844  tree = m_Parser->GetTokenTree();
845 
847 
848  // all tokens, no AI whatsoever
849  for (size_t i = 0; i < tree->size(); ++i)
850  result.insert(i);
851 
853 
854  return result.size();
855  }
856 
857  // we have correctly collected all the tokens, so we will do the artificial intelligence search
858  return AI(result, searchData, wxEmptyString, isPrefix, caseSensitive, &search_scope, caretPos);
859 }
860 
862  bool reallyUseAI,
863  bool isPrefix,
864  bool caseSensitive,
865  int caretPos)
866 {
867  if (s_DebugSmartSense)
868  CCLogger::Get()->DebugLog(F(_T("MarkItemsByAI_1()")));
869 
871  if (!editor)
872  return 0;
873 
874  ccSearchData searchData = { editor->GetControl(), editor->GetFilename() };
875  if (!searchData.control)
876  return 0;
877 
878  TRACE(_T("NativeParser::MarkItemsByAI_1()"));
879 
880  return MarkItemsByAI(&searchData, result, reallyUseAI, isPrefix, caseSensitive, caretPos);
881 }
882 
883 int NativeParser::GetCallTips(wxArrayString& items, int& typedCommas, cbEditor* ed, int pos)
884 {
885  items.Clear();
886  typedCommas = 0;
887  int commas = 0;
888 
889  if (!ed || !m_Parser->Done())
890  {
891  items.Add(wxT("Parsing at the moment..."));
892  return wxSCI_INVALID_POSITION;
893  }
894 
895  TRACE(_T("NativeParser::GetCallTips()"));
896 
897  ccSearchData searchData = { ed->GetControl(), ed->GetFilename() };
898  if (pos == wxNOT_FOUND)
899  pos = searchData.control->GetCurrentPos();
900  int nest = 0;
901  while (--pos > 0)
902  {
903  const int style = searchData.control->GetStyleAt(pos);
904  if ( searchData.control->IsString(style)
905  || searchData.control->IsCharacter(style)
906  || searchData.control->IsComment(style) )
907  {
908  continue;
909  }
910 
911  const wxChar ch = searchData.control->GetCharAt(pos);
912  if (ch == _T(';'))
913  return wxSCI_INVALID_POSITION;
914  else if (ch == _T(','))
915  {
916  if (nest == 0)
917  ++commas;
918  }
919  else if (ch == _T(')'))
920  --nest;
921  else if (ch == _T('('))
922  {
923  ++nest;
924  if (nest > 0)
925  break;
926  }
927  }// while
928 
929  // strip un-wanted
930  while (--pos > 0)
931  {
932  if ( searchData.control->GetCharAt(pos) <= _T(' ')
933  || searchData.control->IsComment(searchData.control->GetStyleAt(pos)) )
934  {
935  continue;
936  }
937  break;
938  }
939 
940  const int start = searchData.control->WordStartPosition(pos, true);
941  const int end = searchData.control->WordEndPosition(pos, true);
942  const wxString target = searchData.control->GetTextRange(start, end);
943  TRACE(_T("Sending \"%s\" for call-tip"), target.wx_str());
944  if (target.IsEmpty())
945  return wxSCI_INVALID_POSITION;
946 
947  TokenIdxSet result;
948  MarkItemsByAI(result, true, false, true, end);
949 
950  ComputeCallTip(m_Parser->GetTokenTree(), result, items);
951 
952  typedCommas = commas;
953  TRACE(_T("NativeParser::GetCallTips(): typedCommas=%d"), typedCommas);
954  items.Sort();
955  return end;
956 }
957 
959 {
960  ProjectSearchDirsMap::iterator it;
961  it = m_ProjectSearchDirsMap.find(project);
962  if (it == m_ProjectSearchDirsMap.end())
963  it = m_ProjectSearchDirsMap.insert(m_ProjectSearchDirsMap.end(), std::make_pair(project, wxArrayString()));
964 
965  return it->second;
966 }
967 
969 {
970 #if wxCHECK_VERSION(3, 0, 0)
971  return;
972 #endif // wxCHECK_VERSION
973 
974  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
975  if (m_ClassBrowser || !cfg->ReadBool(_T("/use_symbols_browser"), true))
976  return;
977 
978  TRACE(_T("NativeParser::CreateClassBrowser(): Enter"));
979 
980  m_ClassBrowserIsFloating = cfg->ReadBool(_T("/as_floating_window"), false);
981 
983  {
984  m_ClassBrowser = new ClassBrowser(Manager::Get()->GetAppWindow(), this);
985 
986  // make this a free floating/docking window
988 
989  evt.name = _T("SymbolsBrowser");
990  evt.title = _("Symbols browser");
991  evt.pWindow = m_ClassBrowser;
993  evt.desiredSize.Set(200, 250);
994  evt.floatingSize.Set(200, 250);
995  evt.minimumSize.Set(150, 150);
996  evt.shown = true;
997  evt.hideable = true;
998  Manager::Get()->ProcessEvent(evt);
1000  }
1001  else
1002  {
1003  // make this a tab in projectmanager notebook
1004  m_ClassBrowser = new ClassBrowser(Manager::Get()->GetProjectManager()->GetUI().GetNotebook(), this);
1007  }
1008 
1009  // Dreaded DDE-open bug related: do not touch unless for a good reason
1010  // TODO (Morten): ? what's bug? I test it, it's works well now.
1011  m_ClassBrowser->SetParser(m_Parser); // Also updates class browser
1012 
1013  TRACE(_T("NativeParser::CreateClassBrowser(): Leave"));
1014 }
1015 
1016 void NativeParser::RemoveClassBrowser(cb_unused bool appShutDown)
1017 {
1018  if (!m_ClassBrowser)
1019  return;
1020 
1021  TRACE(_T("NativeParser::RemoveClassBrowser()"));
1022 
1024  {
1026  evt.pWindow = m_ClassBrowser;
1027  Manager::Get()->ProcessEvent(evt);
1028  }
1029  else
1030  {
1032  if (idx != -1)
1034  }
1035  m_ClassBrowser->Destroy();
1036  m_ClassBrowser = NULL;
1037 }
1038 
1040 {
1041  if (!m_ClassBrowser)
1042  return;
1043 
1044  TRACE(_T("NativeParser::UpdateClassBrowser()"));
1045 
1046  if ( m_Parser != m_TempParser
1047  && m_Parser->Done()
1049  {
1051  }
1052 }
1053 
1055 {
1056  if (!parser)
1057  return false;
1058 
1059  TRACE(_T("NativeParser::DoFullParsing(): Enter"));
1060 
1061  if (!AddCompilerDirs(project, parser))
1062  CCLogger::Get()->DebugLog(_T("NativeParser::DoFullParsing(): AddCompilerDirs failed!"));
1063 
1064  if (!AddCompilerPredefinedMacros(project, parser))
1065  CCLogger::Get()->DebugLog(_T("NativeParser::DoFullParsing(): AddCompilerPredefinedMacros failed!"));
1066 
1067  if (!AddProjectDefinedMacros(project, parser))
1068  CCLogger::Get()->DebugLog(_T("NativeParser::DoFullParsing(): AddProjectDefinedMacros failed!"));
1069 
1070  // add per-project dirs
1071  if (project)
1072  {
1073  if ( !parser->Options().platformCheck
1074  || (parser->Options().platformCheck && project->SupportsCurrentPlatform()) )
1075  {
1077  project->GetBasePath(), parser);
1078  }
1079  }
1080 
1081  StringList localSources;
1082 
1083  if (project)
1084  {
1085  for (FilesList::const_iterator fl_it = project->GetFilesList().begin();
1086  fl_it != project->GetFilesList().end(); ++fl_it)
1087  {
1088  ProjectFile* pf = *fl_it;
1089  if (!pf)
1090  continue;
1091  // check the file types in the project files
1093  if (ft == ParserCommon::ftSource) // parse source files
1094  {
1095  localSources.push_back(pf->file.GetFullPath());
1096  }
1097  }
1098  }
1099 
1100  CCLogger::Get()->DebugLog(_T("NativeParser::DoFullParsing(): Adding cpp/c files to batch-parser"));
1101 
1102  // parse priority files
1103  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
1104 
1105 
1106  if (!localSources.empty())
1107  {
1108  CCLogger::Get()->DebugLog(F(_T("NativeParser::DoFullParsing(): Added %lu source file(s) for project '%s' to batch-parser..."),
1109  static_cast<unsigned long>( localSources.size()), prj.wx_str()));
1110 
1111  // local source files added to Parser
1112  parser->AddBatchParse(localSources);
1113  }
1114 
1115  TRACE(_T("NativeParser::DoFullParsing(): Leave"));
1116 
1117  return true;
1118 }
1119 
1121 {
1122  if (!parser || parser == m_Parser || GetParserByProject(project) != parser)
1123  {
1124  TRACE(_T("NativeParser::SwitchParser(): No need to / cannot switch."));
1125  return false;
1126  }
1127 
1128  TRACE(_T("NativeParser::SwitchParser()"));
1129 
1130  SetParser(parser); // Also updates class browser
1131 
1132  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
1133  wxString log(F(_("Switch parser to project '%s'"), prj.wx_str()));
1134  CCLogger::Get()->Log(log);
1135  CCLogger::Get()->DebugLog(log);
1136 
1137  return true;
1138 }
1139 
1141 {
1142  // the active parser is the same as the old active parser, nothing need to be done
1143  if (m_Parser == parser)
1144  return;
1145 
1146  // a new parser is active, so remove the old parser's local variable tokens.
1147  // if m_Parser == nullptr, this means the active parser is already deleted.
1148  if (m_Parser)
1150 
1151  // refresh code completion related variables
1153 
1154  // switch the active parser
1155  m_Parser = parser;
1156 
1157  if (m_ClassBrowser)
1158  m_ClassBrowser->SetParser(parser); // Also updates class browser
1159 }
1160 
1162 {
1163  TRACE(_T("NativeParser::ClearParsers()"));
1164 
1166  {
1167  while (!m_ParsedProjects.empty() && DeleteParser(*m_ParsedProjects.begin()))
1168  ;
1169  }
1170  else
1171  {
1172  while (!m_ParserList.empty() && DeleteParser(m_ParserList.begin()->first))
1173  ;
1174  }
1175 }
1176 
1178 {
1179  TRACE(_T("NativeParser::RemoveObsoleteParsers(): Enter"));
1180 
1181  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
1182  const size_t maxParsers = cfg->ReadInt(_T("/max_parsers"), 5);
1183  wxArrayString removedProjectNames;
1184  std::pair<cbProject*, ParserBase*> info = GetParserInfoByCurrentEditor();
1185 
1186  while (m_ParserList.size() > maxParsers)
1187  {
1188  bool deleted = false;
1189  for (ParserList::const_iterator it = m_ParserList.begin(); it != m_ParserList.end(); ++it)
1190  {
1191  if (it->second == info.second)
1192  continue;
1193 
1194  wxString prj = (it->first ? it->first->GetTitle() : _T("*NONE*"));
1195  if ( DeleteParser(it->first) )
1196  {
1197  // Please note that DeleteParser() may erase one element of the m_ParserList, so
1198  // do NOT use the constant iterator here again, as the element pointed by it may be
1199  // destroyed in DeleteParser().
1200  removedProjectNames.Add(prj);
1201  deleted = true;
1202  break;
1203  }
1204  }
1205 
1206  if (!deleted)
1207  break;
1208  }
1209 
1210  for (size_t i = 0; i < removedProjectNames.GetCount(); ++i)
1211  {
1212  wxString log(F(_("NativeParser::RemoveObsoleteParsers():Removed obsolete parser of '%s'"), removedProjectNames[i].wx_str()));
1213  CCLogger::Get()->Log(log);
1214  CCLogger::Get()->DebugLog(log);
1215  }
1216 
1217  TRACE(_T("NativeParser::RemoveObsoleteParsers(): Leave"));
1218 }
1219 
1220 std::pair<cbProject*, ParserBase*> NativeParser::GetParserInfoByCurrentEditor()
1221 {
1222  std::pair<cbProject*, ParserBase*> info(nullptr, nullptr);
1224 
1225  if ( editor ) //No need to check editor->GetFilename, because a built-in editor always have a filename
1226  {
1227  info.first = GetProjectByEditor(editor);
1228  info.second = GetParserByProject(info.first);
1229  }
1230 
1231  return info;
1232 }
1233 
1234 #ifdef __WXMSW__
1235 void NativeParser::SetTokenKindImage(int kind, const wxBitmap& bitmap, const wxBitmap& mask)
1236 {
1237  if (kind < PARSER_IMG_MIN || kind > PARSER_IMG_MAX)
1238  return;
1239  m_ImageList->Replace(kind, bitmap, mask);
1240 }
1241 #else
1242 void NativeParser::SetTokenKindImage(int WXUNUSED(kind), const wxBitmap& WXUNUSED(bitmap), const wxBitmap& WXUNUSED(mask))
1243 {
1244  return;
1245 }
1246 #endif
1247 
1248 void NativeParser::SetTokenKindImage(int kind, const wxBitmap& bitmap, cb_unused const wxColour& maskColour)
1249 {
1250  if (kind < PARSER_IMG_MIN || kind > PARSER_IMG_MAX)
1251  return;
1252  m_ImageList->Replace(kind, bitmap);//, maskColour);
1253 }
1254 
1255 void NativeParser::SetTokenKindImage(int kind, const wxIcon& icon)
1256 {
1257  if (kind < PARSER_IMG_MIN || kind > PARSER_IMG_MAX)
1258  return;
1259  m_ImageList->Replace(kind, icon);
1260 }
1261 
1263 {
1264  m_Parser->ClassBrowserOptions().showInheritance = (mode == bvmInheritance) ? true : false;
1266 }
1267 
1268 void NativeParser::OnProjectLoadingHook(cbProject* project, TiXmlElement* elem, bool loading)
1269 {
1270  if (loading)
1271  {
1272  // Hook called when loading project file.
1273  wxArrayString& pdirs = GetProjectSearchDirs(project);
1274 
1275  TiXmlElement* CCConf = elem->FirstChildElement("code_completion");
1276  if (CCConf)
1277  {
1278  TiXmlElement* pathsElem = CCConf->FirstChildElement("search_path");
1279  while (pathsElem)
1280  {
1281  if (pathsElem->Attribute("add"))
1282  {
1283  wxString dir = cbC2U(pathsElem->Attribute("add"));
1284  if (pdirs.Index(dir) == wxNOT_FOUND)
1285  pdirs.Add(dir);
1286  }
1287 
1288  pathsElem = pathsElem->NextSiblingElement("search_path");
1289  }
1290  }
1291  }
1292  else
1293  {
1294  // Hook called when saving project file.
1295  wxArrayString& pdirs = GetProjectSearchDirs(project);
1296 
1297  // since rev4332, the project keeps a copy of the <Extensions> element
1298  // and re-uses it when saving the project (so to avoid losing entries in it
1299  // if plugins that use that element are not loaded atm).
1300  // so, instead of blindly inserting the element, we must first check it's
1301  // not already there (and if it is, clear its contents)
1302  TiXmlElement* node = elem->FirstChildElement("code_completion");
1303  if (!node)
1304  node = elem->InsertEndChild(TiXmlElement("code_completion"))->ToElement();
1305  if (node)
1306  {
1307  node->Clear();
1308  for (size_t i = 0; i < pdirs.GetCount(); ++i)
1309  {
1310  TiXmlElement* path = node->InsertEndChild(TiXmlElement("search_path"))->ToElement();
1311  if (path) path->SetAttribute("add", cbU2C(pdirs[i]));
1312  }
1313  }
1314  }
1315 }
1316 
1317 // helper funcs
1318 
1319 // Start an Artificial Intelligence (!) sequence to gather all the matching tokens..
1320 // The actual AI is in FindAIMatches() below...
1322  ccSearchData* searchData,
1323  const wxString& lineText,
1324  bool isPrefix,
1325  bool caseSensitive,
1326  TokenIdxSet* search_scope,
1327  int caretPos)
1328 {
1329  m_LastAISearchWasGlobal = false;
1331 
1332  int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos;
1333  if (pos < 0 || pos > searchData->control->GetLength())
1334  return 0;
1335 
1336  int line = searchData->control->LineFromPosition(pos);
1337 
1338  // Get the actual search text, such as "objA.m_aaa.m_bbb"
1339  wxString actual_search(lineText);
1340  if (actual_search.IsEmpty())
1341  {
1342  // Get the position at the start of current line
1343  const int startPos = searchData->control->PositionFromLine(line);
1344  actual_search = searchData->control->GetTextRange(startPos, pos).Trim();
1345  }
1346 
1347  // Do the whole job here
1348  if (s_DebugSmartSense)
1349  {
1350  CCLogger::Get()->DebugLog(_T("AI() ========================================================="));
1351  CCLogger::Get()->DebugLog(F(_T("AI() Doing AI for '%s':"), actual_search.wx_str()));
1352  }
1353  TRACE(_T("NativeParser::AI()"));
1354 
1355  TokenTree* tree = m_Parser->GetTokenTree();
1356 
1357  // find current function's namespace so we can include local scope's tokens
1358  // we ' ll get the function's token (all matches) and add its parent namespace
1359  TokenIdxSet proc_result;
1360  size_t found_at = FindCurrentFunctionToken(searchData, proc_result, pos);
1361 
1362  TokenIdxSet scope_result;
1363  if (found_at)
1364  FindCurrentFunctionScope(tree, proc_result, scope_result);
1365 
1366  // add additional search scopes???
1367  // for example, we are here:
1368  /* void ClassA::FunctionB(int paraC){
1369  m_aaa
1370  */
1371  // then, ClassA should be added as a search_scope, the global scope should be added too.
1372 
1373  // if search_scope is already defined, then, add scope_result to search_scope
1374  // otherwise we just set search_scope as scope_result
1375  if (!search_scope)
1376  search_scope = &scope_result;
1377  else
1378  {
1379  // add scopes, "tis" refer to "token index set"
1380  for (TokenIdxSet::const_iterator tis_it = scope_result.begin(); tis_it != scope_result.end(); ++tis_it)
1381  search_scope->insert(*tis_it);
1382  }
1383 
1384  // remove non-namespace/class tokens
1385  CleanupSearchScope(tree, search_scope);
1386 
1387  // find all other matches
1388  std::queue<ParserComponent> components;
1389  BreakUpComponents(actual_search, components);
1390 
1391  m_LastAISearchWasGlobal = components.size() <= 1;
1392  if (!components.empty())
1393  m_LastAIGlobalSearch = components.front().component;
1394 
1395  ResolveExpression(tree, components, *search_scope, result, caseSensitive, isPrefix);
1396 
1397  if (s_DebugSmartSense)
1398  CCLogger::Get()->DebugLog(F(_T("AI() AI leave, returned %lu results"),static_cast<unsigned long>(result.size())));
1399 
1400  return result.size();
1401 }
1402 
1403 // find a function where current caret located.
1404 // We need to find extra class scope, otherwise, we will failed do the cc in a class declaration
1405 size_t NativeParser::FindCurrentFunctionToken(ccSearchData* searchData, TokenIdxSet& result, int caretPos)
1406 {
1407  TokenIdxSet scope_result;
1408  wxString procName;
1409  wxString scopeName;
1410  FindCurrentFunctionStart(searchData, &scopeName, &procName, nullptr, caretPos);
1411 
1412  if (procName.IsEmpty())
1413  return 0;
1414 
1415  // add current scope
1416  if (!scopeName.IsEmpty())
1417  {
1418  // _namespace ends with double-colon (::). remove it
1419  scopeName.RemoveLast();
1420  scopeName.RemoveLast();
1421 
1422  // search for namespace
1423  std::queue<ParserComponent> ns;
1424  BreakUpComponents(scopeName, ns);
1425 
1427 
1428  // No critical section needed in this recursive function!
1429  // All functions that call this recursive FindAIMatches function, should already entered a critical section.
1430  FindAIMatches(m_Parser->GetTokenTree(), ns, scope_result, -1,
1431  true, true, false, tkNamespace | tkClass | tkTypedef);
1432 
1434  }
1435 
1436  // if no scope, use global scope
1437  if (scope_result.empty())
1438  scope_result.insert(-1);
1439 
1441 
1442  for (TokenIdxSet::const_iterator tis_it = scope_result.begin(); tis_it != scope_result.end(); ++tis_it)
1443  {
1444  GenerateResultSet(m_Parser->GetTokenTree(), procName, *tis_it, result,
1445  true, false, tkAnyFunction | tkClass);
1446  }
1447 
1449 
1450  return result.size();
1451 }
1452 
1453 // returns current function's position (not line) in the editor
1455  wxString* nameSpace,
1456  wxString* procName,
1457  int* functionIndex,
1458  int caretPos)
1459 {
1460  // cache last result for optimization
1461  int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos;
1462  if ((pos < 0) || (pos > searchData->control->GetLength()))
1463  {
1464  if (s_DebugSmartSense)
1465  CCLogger::Get()->DebugLog(F(_T("FindCurrentFunctionStart() Cannot determine position. caretPos=%d, control=%d"),
1466  caretPos, searchData->control->GetCurrentPos()));
1467  return -1;
1468  }
1469 
1470  TRACE(_T("NativeParser::FindCurrentFunctionStart()"));
1471 
1472  const int curLine = searchData->control->LineFromPosition(pos) + 1;
1473  if ( (curLine == m_LastLine)
1474  && ( (searchData->control == m_LastControl) && (!searchData->control->GetModify()) )
1475  && (searchData->file == m_LastFile) )
1476  {
1477  if (nameSpace) *nameSpace = m_LastNamespace;
1478  if (procName) *procName = m_LastPROC;
1479  if (functionIndex) *functionIndex = m_LastFunctionIndex;
1480 
1481  if (s_DebugSmartSense)
1482  CCLogger::Get()->DebugLog(F(_T("FindCurrentFunctionStart() Cached namespace='%s', cached proc='%s' (returning %d)"),
1484 
1485  return m_LastResult;
1486  }
1487 
1488  if (s_DebugSmartSense)
1489  CCLogger::Get()->DebugLog(F(_T("FindCurrentFunctionStart() Looking for tokens in '%s'"),
1490  searchData->file.wx_str()));
1491  m_LastFile = searchData->file;
1492  m_LastControl = searchData->control;
1493  m_LastLine = curLine;
1494 
1495  // we have all the tokens in the current file, then just do a loop on all
1496  // the tokens, see if the line is in the token's imp.
1497  TokenIdxSet result;
1498  size_t num_results = m_Parser->FindTokensInFile(searchData->file, result, tkAnyFunction | tkClass);
1499  if (s_DebugSmartSense)
1500  CCLogger::Get()->DebugLog(F(_T("FindCurrentFunctionStart() Found %lu results"), static_cast<unsigned long>(num_results)));
1501 
1502  TokenTree* tree = m_Parser->GetTokenTree();
1503 
1505 
1506  const int idx = GetTokenFromCurrentLine(tree, result, curLine, searchData->file);
1507  const Token* token = tree->at(idx);
1508  if (token)
1509  {
1510  // got it :)
1511  if (s_DebugSmartSense)
1512  CCLogger::Get()->DebugLog(F(_T("FindCurrentFunctionStart() Current function: '%s' (at line %u)"),
1513  token->DisplayName().wx_str(),
1514  token->m_ImplLine));
1515 
1516  m_LastNamespace = token->GetNamespace();
1517  m_LastPROC = token->m_Name;
1518  m_LastFunctionIndex = token->m_Index;
1519  m_LastResult = searchData->control->PositionFromLine(token->m_ImplLine - 1);
1520 
1521  // locate function's opening brace
1522  if (token->m_TokenKind & tkAnyFunction)
1523  {
1524  while (m_LastResult < searchData->control->GetTextLength())
1525  {
1526  wxChar ch = searchData->control->GetCharAt(m_LastResult);
1527  if (ch == _T('{'))
1528  break;
1529  else if (ch == 0)
1530  {
1531  if (s_DebugSmartSense)
1532  CCLogger::Get()->DebugLog(_T("FindCurrentFunctionStart() Can't determine functions opening brace..."));
1533 
1535  return -1;
1536  }
1537 
1538  ++m_LastResult;
1539  }
1540  }
1541 
1542  if (nameSpace) *nameSpace = m_LastNamespace;
1543  if (procName) *procName = m_LastPROC;
1544  if (functionIndex) *functionIndex = token->m_Index;
1545 
1546  if (s_DebugSmartSense)
1547  CCLogger::Get()->DebugLog(F(_T("FindCurrentFunctionStart() Namespace='%s', proc='%s' (returning %d)"),
1549 
1551  return m_LastResult;
1552  }
1553 
1555 
1556  if (s_DebugSmartSense)
1557  CCLogger::Get()->DebugLog(_T("FindCurrentFunctionStart() Can't determine current function..."));
1558 
1559  m_LastResult = -1;
1560  return -1;
1561 }
1562 
1563 bool NativeParser::ParseUsingNamespace(ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos)
1564 {
1565  if (s_DebugSmartSense)
1566  CCLogger::Get()->DebugLog(_T("ParseUsingNamespace() Parse file scope for \"using namespace\""));
1567  TRACE(_T("NativeParser::ParseUsingNamespace()"));
1568 
1569  int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos;
1570  if (pos < 0 || pos > searchData->control->GetLength())
1571  return false;
1572 
1573  // Get the buffer from begin of the editor to the current caret position
1574  wxString buffer = searchData->control->GetTextRange(0, pos);
1575 
1576  return ParseBufferForUsingNamespace(buffer, search_scope);
1577 }
1578 
1579 bool NativeParser::ParseBufferForUsingNamespace(const wxString& buffer, TokenIdxSet& search_scope, bool bufferSkipBlocks)
1580 {
1581  wxArrayString ns;
1582  m_Parser->ParseBufferForUsingNamespace(buffer, ns, bufferSkipBlocks);
1583 
1584  TokenTree* tree = m_Parser->GetTokenTree();
1585 
1587 
1588  for (size_t i = 0; i < ns.GetCount(); ++i)
1589  {
1590  std::queue<ParserComponent> components;
1591  BreakUpComponents(ns[i], components);
1592 
1593  int parentIdx = -1;
1594  while (!components.empty())
1595  {
1596  ParserComponent pc = components.front();
1597  components.pop();
1598 
1599  int id = tree->TokenExists(pc.component, parentIdx, tkNamespace);
1600  if (id == -1)
1601  {
1602  parentIdx = -1;
1603  break;
1604  }
1605  parentIdx = id;
1606  }
1607 
1608  if (s_DebugSmartSense && parentIdx != -1)
1609  {
1610  const Token* token = tree->at(parentIdx);
1611  if (token)
1612  CCLogger::Get()->DebugLog(F(_T("ParseUsingNamespace() Found %s%s"),
1613  token->GetNamespace().wx_str(), token->m_Name.wx_str()));
1614  }
1615  search_scope.insert(parentIdx);
1616  }
1617 
1619 
1620  return true;
1621 }
1622 
1624 {
1625  if (s_DebugSmartSense)
1626  CCLogger::Get()->DebugLog(_T("ParseFunctionArguments() Parse function arguments"));
1627  TRACE(_T("NativeParser::ParseFunctionArguments()"));
1628 
1629  TokenIdxSet proc_result;
1630 
1631  TokenTree* tree = m_Parser->GetTokenTree(); // the one used inside FindCurrentFunctionToken, FindAIMatches and GenerateResultSet
1632 
1633  size_t found_at = FindCurrentFunctionToken(searchData, proc_result, caretPos);
1634  if (!found_at)
1635  {
1636  if (s_DebugSmartSense)
1637  CCLogger::Get()->DebugLog(_T("ParseFunctionArguments() Could not determine current function's namespace..."));
1638  TRACE(_T("ParseFunctionArguments() Could not determine current function's namespace..."));
1639  return false;
1640  }
1641 
1642  const int pos = caretPos == -1 ? searchData->control->GetCurrentPos() : caretPos;
1643  const unsigned int curLine = searchData->control->LineFromPosition(pos) + 1;
1644 
1645  bool locked = false;
1646  for (TokenIdxSet::const_iterator tis_it = proc_result.begin(); tis_it != proc_result.end(); ++tis_it)
1647  {
1648  wxString buffer;
1649  int initLine = -1;
1650  int tokenIdx = -1;
1651 
1652  if (locked)
1654 
1656  locked = true;
1657 
1658  const Token* token = tree->at(*tis_it);
1659 
1660  if (!token)
1661  continue;
1662  if (curLine < token->m_ImplLineStart || curLine > token->m_ImplLineEnd)
1663  continue;
1664 
1665  if (s_DebugSmartSense)
1666  CCLogger::Get()->DebugLog(_T("ParseFunctionArguments() + Function match: ") + token->m_Name);
1667  TRACE(_T("ParseFunctionArguments() + Function match: ") + token->m_Name);
1668 
1669  if (!token->m_Args.IsEmpty() && !token->m_Args.Matches(_T("()")))
1670  {
1671  buffer = token->m_Args;
1672  // Now we have something like "(int my_int, const TheClass* my_class, float f)"
1673  buffer.Remove(0, 1); // remove (
1674  buffer.RemoveLast(); // remove )
1675  // Now we have "int my_int, const TheClass* my_class, float f"
1676  buffer.Replace(_T(","), _T(";")); // replace commas with semi-colons
1677  // Now we have "int my_int; const TheClass* my_class; float f"
1678  buffer << _T(';'); // aid parser ;)
1679  // Finally we have "int my_int; const TheClass* my_class; float f;"
1680  buffer.Trim();
1681 
1682  if (s_DebugSmartSense)
1683  CCLogger::Get()->DebugLog(F(_T("ParseFunctionArguments() Parsing arguments: \"%s\""), buffer.wx_str()));
1684 
1685  if (!buffer.IsEmpty())
1686  {
1687  const int textLength= searchData->control->GetLength();
1688  if (textLength == -1)
1689  continue;
1690  int paraPos = searchData->control->PositionFromLine(token->m_ImplLine - 1);
1691  if (paraPos == -1)
1692  continue;
1693  while (paraPos < textLength && searchData->control->GetCharAt(paraPos++) != _T('('))
1694  ;
1695  while (paraPos < textLength && searchData->control->GetCharAt(paraPos++) < _T(' '))
1696  ;
1697  initLine = searchData->control->LineFromPosition(paraPos) + 1;
1698  if (initLine == -1)
1699  continue;
1700  tokenIdx = token->m_Index;
1701  }
1702  }
1703 
1705  locked = false;
1706 
1707  if ( !buffer.IsEmpty()
1708  && !m_Parser->ParseBuffer(buffer, false, false, true, searchData->file, tokenIdx, initLine)
1709  && s_DebugSmartSense)
1710  {
1711  CCLogger::Get()->DebugLog(_T("ParseFunctionArguments() Error parsing arguments."));
1712  }
1713  }
1714 
1715  if (locked)
1717 
1718  return true;
1719 }
1720 
1721 bool NativeParser::ParseLocalBlock(ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos)
1722 {
1723  if (s_DebugSmartSense)
1724  CCLogger::Get()->DebugLog(_T("ParseLocalBlock() Parse local block"));
1725  TRACE(_T("NativeParser::ParseLocalBlock()"));
1726 
1727  int parentIdx = -1;
1728  int blockStart = FindCurrentFunctionStart(searchData, nullptr, nullptr, &parentIdx, caretPos);
1729  int initLine = 0;
1730  if (parentIdx != -1)
1731  {
1732  TokenTree* tree = m_Parser->GetTokenTree();
1733 
1735 
1736  const Token* parent = tree->at(parentIdx);
1737  if (parent && (parent->m_TokenKind & tkAnyFunction))
1738  {
1739  m_LastFuncTokenIdx = parent->m_Index;
1740  initLine = parent->m_ImplLineStart;
1741  }
1742 
1744 
1745  // only need to parse the function body, other type of Tokens' body such as class declaration
1746  // should not be parsed.
1747  if (!parent || !(parent->m_TokenKind & tkAnyFunction))
1748  return false;
1749  }
1750 
1751  if (blockStart != -1)
1752  {
1753  cbStyledTextCtrl* stc = searchData->control;
1754  // if we are in a function body, then blockStart points to the '{', so we just skip the '{'.
1755  if (stc->GetCharAt(blockStart) == wxT('{'))
1756  ++blockStart;
1757  const int pos = (caretPos == -1 ? stc->GetCurrentPos() : caretPos);
1758  const int line = stc->LineFromPosition(pos);
1759  const int blockEnd = stc->GetLineEndPosition(line);
1760  if (blockEnd < 0 || blockEnd > stc->GetLength())
1761  {
1762  if (s_DebugSmartSense)
1763  {
1764  CCLogger::Get()->DebugLog(F(_T("ParseLocalBlock() ERROR blockEnd=%d and edLength=%d?!"),
1765  blockEnd, stc->GetLength()));
1766  }
1767  return false;
1768  }
1769 
1770  if (blockStart >= blockEnd)
1771  blockStart = blockEnd;
1772 
1773 // wxString buffer = searchData->control->GetTextRange(blockStart, blockEnd);
1774  wxString buffer;
1775  // condense out-of-scope braces {...}
1776  int scanPos = blockEnd;
1777  for (int curPos = pos; curPos > blockStart; --curPos)
1778  {
1779  if (stc->GetCharAt(curPos) != wxT('}'))
1780  continue;
1781  const int style = stc->GetStyleAt(curPos);
1782  if ( stc->IsString(style)
1783  || stc->IsCharacter(style)
1784  || stc->IsComment(style))
1785  {
1786  continue;
1787  }
1788  const int scopeStart = stc->BraceMatch(curPos);
1789  if (scopeStart < blockStart)
1790  break;
1791  buffer.Prepend(stc->GetTextRange(curPos, scanPos));
1792  int startLn = stc->LineFromPosition(scopeStart);
1793  int endLn = stc->LineFromPosition(curPos);
1794  if (startLn < endLn) // maintain correct line numbers for parsed tokens
1795  buffer.Prepend( wxString(wxT('\n'), endLn - startLn) );
1796  scanPos = scopeStart + 1;
1797  curPos = scopeStart;
1798 
1799  // condense out-of-scope for/if/while declarations
1800  int prevCharIdx = scopeStart - 1;
1801  for (; prevCharIdx > blockStart; --prevCharIdx)
1802  {
1803  if (stc->IsComment(stc->GetStyleAt(prevCharIdx)))
1804  continue;
1805  if (!wxIsspace(stc->GetCharAt(prevCharIdx)))
1806  break;
1807  }
1808  if (stc->GetCharAt(prevCharIdx) != wxT(')'))
1809  continue;
1810  const int paramStart = stc->BraceMatch(prevCharIdx);
1811  if (paramStart < blockStart)
1812  continue;
1813  for (prevCharIdx = paramStart - 1; prevCharIdx > blockStart; --prevCharIdx)
1814  {
1815  if (stc->IsComment(stc->GetStyleAt(prevCharIdx)))
1816  continue;
1817  if (!wxIsspace(stc->GetCharAt(prevCharIdx)))
1818  break;
1819  }
1820  const wxString text = stc->GetTextRange(stc->WordStartPosition(prevCharIdx, true),
1821  stc->WordEndPosition( prevCharIdx, true));
1822  if (text == wxT("for"))
1823  buffer.Prepend(wxT("(;;){"));
1824  else if (text == wxT("if") || text == wxT("while") || text == wxT("catch"))
1825  buffer.Prepend(wxT("(0){"));
1826  else
1827  continue;
1828  startLn = stc->LineFromPosition(prevCharIdx);
1829  endLn = stc->LineFromPosition(scopeStart);
1830  if (startLn < endLn)
1831  buffer.Prepend( wxString(wxT('\n'), endLn - startLn) );
1832  curPos = stc->WordStartPosition(prevCharIdx, true);
1833  scanPos = stc->WordEndPosition( prevCharIdx, true);
1834  }
1835  buffer.Prepend(stc->GetTextRange(blockStart, scanPos));
1836 
1837  buffer.Trim();
1838 
1839  ParseBufferForUsingNamespace(buffer, search_scope, false);
1840 
1841  if ( !buffer.IsEmpty()
1842  && !m_Parser->ParseBuffer(buffer, false, false, true, searchData->file, m_LastFuncTokenIdx, initLine) )
1843  {
1844  if (s_DebugSmartSense)
1845  CCLogger::Get()->DebugLog(_T("ParseLocalBlock() ERROR parsing block:\n") + buffer);
1846  }
1847  else
1848  {
1849  if (s_DebugSmartSense)
1850  {
1851  CCLogger::Get()->DebugLog(F(_T("ParseLocalBlock() Block:\n%s"), buffer.wx_str()));
1852  CCLogger::Get()->DebugLog(_T("ParseLocalBlock() Local tokens:"));
1853 
1854  TokenTree* tree = m_Parser->GetTokenTree();
1855 
1857 
1858  for (size_t i = 0; i < tree->size(); ++i)
1859  {
1860  const Token* token = tree->at(i);
1861  if (token && token->m_IsTemp)
1862  {
1863  wxString log(wxString::Format(_T(" + %s (%d)"), token->DisplayName().wx_str(), token->m_Index));
1864  const Token* parent = tree->at(token->m_ParentIndex);
1865  if (parent)
1866  log += wxString::Format(_T("; Parent = %s (%d)"), parent->m_Name.wx_str(), token->m_ParentIndex);
1867  CCLogger::Get()->DebugLog(log);
1868  }
1869  }
1870 
1872  }
1873  return true;
1874  }
1875  }
1876  else
1877  {
1878  if (s_DebugSmartSense)
1879  CCLogger::Get()->DebugLog(_T("ParseLocalBlock() Could not determine current block start..."));
1880  }
1881  return false;
1882 }
1883 
1885 {
1886  if (!parser)
1887  return false;
1888 
1889  TRACE(_T("NativeParser::AddCompilerDirs(): Enter"));
1890 
1891  // If there is no project, work on default compiler
1892  if (!project)
1893  {
1895  TRACE(_T("NativeParser::AddCompilerDirs(): Leave"));
1896  return true;
1897  }
1898 
1899  // Otherwise (if there is a project), work on the project's compiler...
1900  wxString base = project->GetBasePath();
1901  parser->AddIncludeDir(base); // add project's base path
1902  TRACE(_T("NativeParser::AddCompilerDirs(): Adding project base dir to parser: ") + base);
1903 
1904  // ...so we can access post-processed project's search dirs
1905  Compiler* compiler = CompilerFactory::GetCompiler(project->GetCompilerID());
1906  cb::shared_ptr<CompilerCommandGenerator> generator(compiler ? compiler->GetCommandGenerator(project) : nullptr);
1907 
1908  // get project include dirs
1909  if ( !parser->Options().platformCheck
1910  || (parser->Options().platformCheck && project->SupportsCurrentPlatform()) )
1911  {
1912  AddIncludeDirsToParser(project->GetIncludeDirs(), base, parser);
1913  }
1914 
1915  // alloc array for project compiler AND "no. of targets" times target compilers
1916  int nCompilers = 1 + project->GetBuildTargetsCount();
1917  Compiler** Compilers = new Compiler* [nCompilers];
1918  memset(Compilers, 0, sizeof(Compiler*) * nCompilers);
1919  nCompilers = 0; // reset , use as insert index in the next for loop
1920 
1921  // get targets include dirs
1922  for (int i = 0; i < project->GetBuildTargetsCount(); ++i)
1923  {
1924  ProjectBuildTarget* target = project->GetBuildTarget(i);
1925  if (!target) continue;
1926 
1927  if ( !parser->Options().platformCheck
1928  || (parser->Options().platformCheck && target->SupportsCurrentPlatform()) )
1929  {
1930  // post-processed search dirs (from build scripts)
1931  if (compiler && generator)
1932  AddIncludeDirsToParser(generator->GetCompilerSearchDirs(target), base, parser);
1933 
1934  // apply target vars
1935 // target->GetCustomVars().ApplyVarsToEnvironment();
1936  AddIncludeDirsToParser(target->GetIncludeDirs(), base, parser);
1937 
1938  // get the compiler
1939  wxString CompilerIndex = target->GetCompilerID();
1940  Compiler* tgtCompiler = CompilerFactory::GetCompiler(CompilerIndex);
1941  if (tgtCompiler)
1942  {
1943  Compilers[nCompilers] = tgtCompiler;
1944  ++nCompilers;
1945  }
1946  } // if (target)
1947  } // end loop over the targets
1948 
1949  // add the project compiler to the array of compilers
1950  if (compiler)
1951  { // note it might be possible that this compiler is already in the list
1952  // no need to worry since the compiler list of the parser will filter out duplicate
1953  // entries in the include dir list
1954  Compilers[nCompilers++] = compiler;
1955  }
1956 
1957  // add compiler include dirs
1958  for (int idxCompiler = 0; idxCompiler < nCompilers; ++idxCompiler)
1959  AddCompilerIncludeDirsToParser(Compilers[idxCompiler], parser);
1960 
1961  if (!nCompilers)
1962  CCLogger::Get()->DebugLog(_T("NativeParser::AddCompilerDirs(): No compilers found!"));
1963 
1964  delete [] Compilers;
1965  TRACE(_T("NativeParser::AddCompilerDirs(): Leave"));
1966  return true;
1967 }
1968 
1970 {
1971  if (!parser)
1972  return false;
1973 
1974  if (!parser->Options().wantPreprocessor)
1975  return false;
1976 
1977  TRACE(_T("NativeParser::AddCompilerPredefinedMacros(): Enter"));
1978 
1979  // Default compiler is used for for single file parser (non project)
1980  wxString compilerId = project ? project->GetCompilerID() : CompilerFactory::GetDefaultCompilerID();
1981 
1982  wxString defs;
1983  // gcc
1984  if (compilerId.Contains(_T("gcc")))
1985  {
1986  if ( !AddCompilerPredefinedMacrosGCC(compilerId, project, defs, parser) )
1987  return false;
1988  }
1989  // vc
1990  else if (compilerId.StartsWith(_T("msvc")))
1991  {
1992  if ( !AddCompilerPredefinedMacrosVC(compilerId, defs, parser) )
1993  return false;
1994  }
1995 
1996  TRACE(_T("NativeParser::AddCompilerPredefinedMacros(): Add compiler predefined preprocessor macros:\n%s"), defs.wx_str());
1997  parser->AddPredefinedMacros(defs);
1998 
1999  TRACE(_T("NativeParser::AddCompilerPredefinedMacros(): Leave"));
2000  if ( defs.IsEmpty() )
2001  return false;
2002 
2003  return true;
2004 }
2005 
2006 bool NativeParser::AddCompilerPredefinedMacrosGCC(const wxString& compilerId, cbProject* project, wxString& defs, ParserBase* parser)
2007 {
2008  Compiler* compiler = CompilerFactory::GetCompiler(compilerId);
2009  if (!compiler)
2010  return false;
2011 
2012  if (parser->Options().platformCheck && !compiler->SupportsCurrentPlatform())
2013  {
2014  TRACE(_T("NativeParser::AddCompilerPredefinedMacrosGCC: Not supported on current platform!"));
2015  return false;
2016  }
2017 
2018  wxString masterPath = compiler->GetMasterPath();
2019  Manager::Get()->GetMacrosManager()->ReplaceMacros(masterPath);
2020 #ifdef __WXMSW__
2021  const wxString cpp_compiler = masterPath + _T("\\bin\\") + compiler->GetPrograms().CPP;
2022 #else
2023  const wxString cpp_compiler = masterPath + _T("/bin/") + compiler->GetPrograms().CPP;
2024 #endif
2025  if ( !wxFileName::FileExists(cpp_compiler) )
2026  return false;
2027 
2028  static std::map<wxString, wxString> gccDefsMap;
2029  if (gccDefsMap[cpp_compiler].IsEmpty())
2030  {
2031  static bool reentry = false;
2032  if (reentry)
2033  return false;
2034 
2035  // Check if user set language standard version to use
2036  wxString standard = GetCompilerStandardGCC(compiler, project);
2037 
2038 #ifdef __WXMSW__
2039  const wxString args(wxString::Format(_T(" -E -dM -x c++ %s nul"), standard.wx_str()) );
2040 #else
2041  const wxString args(wxString::Format(_T(" -E -dM -x c++ %s /dev/null"), standard.wx_str()) );
2042 #endif
2043 
2044  wxArrayString output;
2045  reentry = true;
2046  if ( wxExecute(cpp_compiler + args, output, wxEXEC_SYNC | wxEXEC_NODISABLE) == -1 )
2047  {
2048  TRACE(_T("NativeParser::AddCompilerPredefinedMacrosGCC: wxExecute failed!"));
2049  reentry = false;
2050  return false;
2051  }
2052  reentry = false;
2053 
2054  // wxExecute can be a long action and C::B might have been shutdown in the meantime...
2056  return false;
2057 
2058  wxString& gccDefs = gccDefsMap[cpp_compiler];
2059  for (size_t i = 0; i < output.Count(); ++i)
2060  gccDefs += output[i] + _T("\n");
2061 
2062  CCLogger::Get()->DebugLog(_T("NativeParser::AddCompilerPredefinedMacrosGCC: Caching predefined macros for compiler '")
2063  + cpp_compiler + _T("':\n") + gccDefs);
2064  }
2065 
2066  defs = gccDefsMap[cpp_compiler];
2067 
2068  return true;
2069 }
2070 
2072 {
2073  // Check if user set language standard version to use
2074  // 1.) Global compiler settings are first to search in
2076  if (standard.IsEmpty() && project)
2077  {
2078  // 2.) Project compiler setting are second
2079  standard = GetCompilerUsingStandardGCC(project->GetCompilerOptions());
2080 
2081  // 3.) And targets are third in row to look for standard
2082  // NOTE: If two targets use different standards, only the one we
2083  // encounter first (eg. c++98) will be used, and any other
2084  // disregarded (even if it would be c++1y)
2085  if (standard.IsEmpty())
2086  {
2087  for (int i=0; i<project->GetBuildTargetsCount(); ++i)
2088  {
2089  ProjectBuildTarget* target = project->GetBuildTarget(i);
2090  standard = GetCompilerUsingStandardGCC(target->GetCompilerOptions());
2091 
2092  if (!standard.IsEmpty())
2093  break;
2094  }
2095  }
2096  }
2097  return standard;
2098 }
2099 
2101 {
2102  wxString standard;
2103  for (wxArrayString::size_type i=0; i<compilerOptions.Count(); ++i)
2104  {
2105  if (compilerOptions[i].StartsWith(_T("-std=")))
2106  {
2107  standard = compilerOptions[i];
2108  CCLogger::Get()->DebugLog(wxString::Format(_T("NativeParser::GetCompilerUsingStandardGCC(): Using language standard: %s"), standard.wx_str()));
2109  break;
2110  }
2111  }
2112  return standard;
2113 }
2114 
2116 {
2117  static wxString vcDefs;
2118  static bool firstExecute = true;
2119 
2120  if (!firstExecute)
2121  {
2122  defs = vcDefs;
2123  return true;
2124  }
2125 
2126  firstExecute = false;
2127  Compiler* compiler = CompilerFactory::GetCompiler(compilerId);
2128  if (!compiler)
2129  return false;
2130 
2131  if (parser->Options().platformCheck && !compiler->SupportsCurrentPlatform())
2132  {
2133  TRACE(_T("NativeParser::AddCompilerPredefinedMacrosVC: Not supported on current platform!"));
2134  return false;
2135  }
2136 
2137  wxString masterPath = compiler->GetMasterPath();
2138  Manager::Get()->GetMacrosManager()->ReplaceMacros(masterPath);
2139 #ifdef __WXMSW__
2140  const wxString c_compiler = masterPath + _T("\\bin\\") + compiler->GetPrograms().C;
2141 #else
2142  const wxString c_compiler = masterPath + _T("/bin/") + compiler->GetPrograms().C;
2143 #endif
2144  if ( !wxFileName::FileExists(c_compiler) )
2145  return false;
2146 
2147  static bool reentry = false;
2148  if (reentry)
2149  return false;
2150 
2151  wxArrayString output, error;
2152  reentry = true;
2153  // Just run the compiler which shows e.g.:
2154  // "Microsoft (R) C/C++ Optimizing Compiler Version 12.00.8804, for x86", or
2155  // "Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x86"
2156  // ...and extract platform information (32/64 bit) and compiler version (12) out of it
2157  if ( wxExecute(c_compiler, output, error, wxEXEC_SYNC | wxEXEC_NODISABLE) == -1 )
2158  {
2159  TRACE(_T("NativeParser::AddCompilerPredefinedMacrosVC: wxExecute failed!"));
2160  reentry = false;
2161  return false;
2162  }
2163  reentry = false;
2164 
2165  // wxExecute can be a long action and C::B might have been shutdown in the meantime...
2167  return false;
2168 
2169  if (error.IsEmpty())
2170  {
2171  TRACE(_T("NativeParser::AddCompilerPredefinedMacrosVC: Can't get pre-defined macros for MSVC."));
2172  return false;
2173  }
2174 
2175  wxString compilerVersionInfo = error[0];
2176  wxString tmp(_T("Microsoft (R) "));
2177  int pos = compilerVersionInfo.Find(tmp);
2178  if (pos != wxNOT_FOUND)
2179  {
2180  // in earlier versions of MSVC the compiler shows "32 bit" or "64 bit"
2181  // in more recent MSVC version the architecture (x86 or x64) is shown instead
2182  wxString bit = compilerVersionInfo.Mid(pos + tmp.Length(), 2);
2183  if ( (bit.IsSameAs(_T("32"))) || compilerVersionInfo.Contains(_T("x86")) )
2184  defs += _T("#define _WIN32") _T("\n");
2185  else if ( (bit.IsSameAs(_T("64"))) || compilerVersionInfo.Contains(_T("x64")) )
2186  defs += _T("#define _WIN64") _T("\n");
2187  }
2188 
2189  tmp = _T("Compiler Version ");
2190  pos = compilerVersionInfo.Find(tmp);
2191  if (pos != wxNOT_FOUND)
2192  {
2193  wxString ver = compilerVersionInfo.Mid(pos + tmp.Length(), 4); // is i.e. 12.0
2194  pos = ver.Find(_T('.'));
2195  if (pos != wxNOT_FOUND)
2196  {
2197  // out of "12.0" make "1200" for the #define
2198  ver[pos] = ver[pos + 1]; // move the mintor version first number to the dot position
2199  ver[pos + 1] = _T('0'); // add another zero at the end
2200  defs += _T("#define _MSC_VER ") + ver;
2201  // Known to now (see https://en.wikipedia.org/wiki/Visual_C%2B%2B):
2202  // MSVC++ 12.0 _MSC_VER = 1800 (Visual Studio 2013)
2203  // MSVC++ 11.0 _MSC_VER = 1700 (Visual Studio 2012)
2204  // MSVC++ 10.0 _MSC_VER = 1600 (Visual Studio 2010)
2205  // MSVC++ 9.0 _MSC_VER = 1500 (Visual Studio 2008)
2206  // MSVC++ 8.0 _MSC_VER = 1400 (Visual Studio 2005)
2207  // MSVC++ 7.1 _MSC_VER = 1310 (Visual Studio 2003)
2208  // MSVC++ 7.0 _MSC_VER = 1300
2209  // MSVC++ 6.0 _MSC_VER = 1200
2210  // MSVC++ 5.0 _MSC_VER = 1100
2211  }
2212  }
2213 
2214  defs = vcDefs;
2215  return true;
2216 }
2217 
2219 {
2220  if (!parser)
2221  return false;
2222 
2223  if (!project)
2224  return true;
2225 
2226  TRACE(_T("NativeParser::AddProjectDefinedMacros(): Enter"));
2227 
2228  wxString compilerId = project->GetCompilerID();
2229  wxString defineCompilerSwitch(wxEmptyString);
2230  if (compilerId.Contains(_T("gcc")))
2231  defineCompilerSwitch = _T("-D");
2232  else if (compilerId.StartsWith(_T("msvc")))
2233  defineCompilerSwitch = _T("/D");
2234 
2235  if (defineCompilerSwitch.IsEmpty())
2236  return false; // no compiler options, return false
2237 
2238  wxString defs;
2239  wxArrayString opts;
2240  if ( !parser->Options().platformCheck
2241  || (parser->Options().platformCheck && project->SupportsCurrentPlatform()) )
2242  {
2243  opts = project->GetCompilerOptions();
2244  }
2245 
2246  ProjectBuildTarget* target = project->GetBuildTarget(project->GetActiveBuildTarget());
2247  if (target != NULL)
2248  {
2249  if ( !parser->Options().platformCheck
2250  || (parser->Options().platformCheck && target->SupportsCurrentPlatform()) )
2251  {
2252  wxArrayString targetOpts = target->GetCompilerOptions();
2253  for (size_t i = 0; i < targetOpts.GetCount(); ++i)
2254  opts.Add(targetOpts[i]);
2255  }
2256  }
2257  // In case of virtual targets, collect the defines from all child targets.
2259  for (size_t i = 0; i < targets.GetCount(); ++i)
2260  {
2261  target = project->GetBuildTarget(targets[i]);
2262  if (target != NULL)
2263  {
2264  if ( !parser->Options().platformCheck
2265  || (parser->Options().platformCheck && target->SupportsCurrentPlatform()) )
2266  {
2267  wxArrayString targetOpts = target->GetCompilerOptions();
2268  for (size_t j = 0; j < targetOpts.GetCount(); ++j)
2269  opts.Add(targetOpts[j]);
2270  }
2271  }
2272  }
2273 
2274  for (size_t i = 0; i < opts.GetCount(); ++i)
2275  {
2276  wxString def = opts[i];
2278  if ( !def.StartsWith(defineCompilerSwitch) )
2279  continue;
2280 
2281  def = def.Right(def.Length() - defineCompilerSwitch.Length());
2282  int pos = def.Find(_T('='));
2283  if (pos != wxNOT_FOUND)
2284  def[pos] = _T(' ');
2285 
2286  defs += _T("#define ") + def + _T("\n");
2287  }
2288 
2289  TRACE(_T("Add project and current build target defined preprocessor macros:\n%s"), defs.wx_str());
2290  parser->AddPredefinedMacros(defs);
2291  TRACE(_T("NativeParser::AddProjectDefinedMacros(): Leave"));
2292  if ( defs.IsEmpty() )
2293  return false;
2294 
2295  return true;
2296 }
2297 
2299 {
2300  if (!compiler || !parser) return;
2301 
2302  if ( !parser->Options().platformCheck
2303  || (parser->Options().platformCheck && compiler->SupportsCurrentPlatform()) )
2304  {
2305  // these dirs were the user's compiler include search dirs
2306  AddIncludeDirsToParser(compiler->GetIncludeDirs(), wxEmptyString, parser);
2307 
2308  // find out which compiler, if gnu, do the special trick
2309  // to find it's internal include paths
2310  // but do only once per C::B session, thus cache for later calls
2311  if (compiler->GetID().Contains(_T("gcc")))
2312  AddGCCCompilerDirs(compiler->GetMasterPath(), compiler->GetPrograms().CPP, parser);
2313  }
2314 }
2315 
2316 // These dirs are the built-in search dirs of the compiler itself (GCC).
2317 // Such as when you install your MinGW GCC in E:/code/MinGW/bin
2318 // The buildin search dir may contains: E:/code/MinGW/include
2320 {
2321  // keep the gcc compiler path's once if found across C::B session
2322  // makes opening workspaces a *lot* faster by avoiding endless calls to the compiler
2323  static std::map<wxString, wxArrayString> dirs;
2324  static wxArrayString cached_result; // avoid accessing "dirs" too often (re-entry)
2325  cached_result = dirs[cpp_compiler];
2326  if ( !cached_result.IsEmpty() )
2327  return cached_result;
2328 
2329  if ( !wxFileExists(cpp_compiler) )
2330  {
2331  CCLogger::Get()->DebugLog(_T("NativeParser::GetGCCCompilerDirs(): Cannot get compiler dirs due to invalid compiler: ") + cpp_compiler);
2332  return cached_result;
2333  }
2334 
2335  // wxExecute can be a long action and C::B might have been shutdown in the meantime...
2336  // This is here, to protect at re-entry:
2338  return cached_result;
2339 
2340  TRACE(_T("NativeParser::GetGCCCompilerDirs(): Enter"));
2341 
2342  // for starters , only do this for gnu compiler
2343  //CCLogger::Get()->DebugLog(_T("CompilerID ") + CompilerID);
2344  //
2345  // Windows: mingw32-g++ -v -E -x c++ nul
2346  // Linux : g++ -v -E -x c++ /dev/null
2347  // do the trick only for c++, not needed then for C (since this is a subset of C++)
2348 
2349 
2350  // let's construct the command
2351  // use a null file handler
2352  // both works fine in Windows and Linux
2353 
2354  // Different command on Windows
2355  wxString Command = platform::windows ? (cpp_compiler + _T(" -v -E -x c++ nul"))
2356  : (cpp_compiler + _T(" -v -E -x c++ /dev/null"));
2357 
2358  static bool reentry_protection = false;
2359  if (reentry_protection) // still running previous command
2360  return cached_result; // better return previous result...
2361  reentry_protection = true;
2362 
2363  // action time (everything shows up on the error stream)
2364  wxArrayString Output, Errors;
2365  if ( wxExecute(Command, Output, Errors, wxEXEC_SYNC | wxEXEC_NODISABLE) == -1 )
2366  {
2367  TRACE(_T("NativeParser::GetGCCCompilerDirs(): GetGCCCompilerDirs::wxExecute failed!"));
2368  reentry_protection = false;
2369  return cached_result;
2370  }
2371  reentry_protection = false;
2372 
2373  // wxExecute can be a long action and C::B might have been shutdown in the meantime...
2374  // This is here, to protect a long run:
2376  return cached_result;
2377 
2378  // start from "#include <...>", and the path followed
2379  // let's hope this does not change too quickly, otherwise we need
2380  // to adjust our search code (for several versions ...)
2381  bool start = false;
2382  for (size_t idxCount = 0; idxCount < Errors.GetCount(); ++idxCount)
2383  {
2384  wxString path = Errors[idxCount].Trim(true).Trim(false);
2385  if (!start)
2386  {
2387  if (!path.StartsWith(_T("#include <...>")))
2388  continue; // Next for-loop
2389  path = Errors[++idxCount].Trim(true).Trim(false);
2390  start = true;
2391  }
2392 
2393  wxFileName fname(path, wxEmptyString);
2394  fname.Normalize();
2395  fname.SetVolume(fname.GetVolume().MakeUpper());
2396  if (!fname.DirExists())
2397  break;
2398 
2399  dirs[cpp_compiler].Add(fname.GetPath());
2400 
2401  CCLogger::Get()->DebugLog(_T("NativeParser::GetGCCCompilerDirs(): Caching GCC default include dir: ") + fname.GetPath());
2402  }
2403 
2404  TRACE(_T("NativeParser::GetGCCCompilerDirs(): Leave"));
2405  return dirs[cpp_compiler];
2406 }
2407 
2408 void NativeParser::AddGCCCompilerDirs(const wxString& masterPath, const wxString& compilerCpp, ParserBase* parser)
2409 {
2410  wxFileName fn(wxEmptyString, compilerCpp);
2411  wxString masterPathNoMacros(masterPath);
2412  Manager::Get()->GetMacrosManager()->ReplaceMacros(masterPathNoMacros);
2413  fn.SetPath(masterPathNoMacros);
2414  fn.AppendDir(_T("bin"));
2415 
2416  const wxArrayString& gccDirs = GetGCCCompilerDirs(fn.GetFullPath());
2417  TRACE(_T("NativeParser::AddGCCCompilerDirs(): Adding %lu cached gcc dirs to parser..."), static_cast<unsigned long>(gccDirs.GetCount()));
2418  for (size_t i=0; i<gccDirs.GetCount(); ++i)
2419  {
2420  parser->AddIncludeDir(gccDirs[i]);
2421  TRACE(_T("NativeParser::AddGCCCompilerDirs(): Adding cached compiler dir to parser: ") + gccDirs[i]);
2422  }
2423 }
2424 
2426 {
2427  for (unsigned int i = 0; i < dirs.GetCount(); ++i)
2428  {
2429  wxString dir = dirs[i];
2431  if ( !base.IsEmpty() )
2432  {
2433  wxFileName fn(dir);
2434  if ( NormalizePath(fn, base) )
2435  {
2436  parser->AddIncludeDir(fn.GetFullPath());
2437  TRACE(_T("NativeParser::AddIncludeDirsToParser(): Adding directory to parser: ") + fn.GetFullPath());
2438  }
2439  else
2440  CCLogger::Get()->DebugLog(F(_T("NativeParser::AddIncludeDirsToParser(): Error normalizing path: '%s' from '%s'"), dir.wx_str(), base.wx_str()));
2441  }
2442  else
2443  parser->AddIncludeDir(dir); // no base path, nothing to normalise
2444  }
2445 }
2446 
2448 {
2449  TRACE(_T("NativeParser::OnParserStart(): Enter"));
2450 
2451  cbProject* project = static_cast<cbProject*>(event.GetClientData());
2452  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
2453  const ParserCommon::ParserState state = static_cast<ParserCommon::ParserState>(event.GetInt());
2454 
2455  switch (state)
2456  {
2458  CCLogger::Get()->DebugLog(F(_("NativeParser::OnParserStart(): Starting batch parsing for project '%s'..."), prj.wx_str()));
2459  {
2460  std::pair<cbProject*, ParserBase*> info = GetParserInfoByCurrentEditor();
2461  if (info.second && m_Parser != info.second)
2462  {
2463  CCLogger::Get()->DebugLog(_T("NativeParser::OnParserStart(): Start switch from OnParserStart::ptCreateParser"));
2464  SwitchParser(info.first, info.second); // Calls SetParser() which also calls UpdateClassBrowserView()
2465  }
2466  }
2467  break;
2468 
2470  CCLogger::Get()->DebugLog(F(_("NativeParser::OnParserStart(): Starting add file parsing for project '%s'..."), prj.wx_str()));
2471  break;
2472 
2474  CCLogger::Get()->DebugLog(F(_("NativeParser::OnParserStart(): Starting re-parsing for project '%s'..."), prj.wx_str()));
2475  break;
2476 
2478  if (event.GetString().IsEmpty())
2479  CCLogger::Get()->DebugLog(F(_("NativeParser::OnParserStart(): Batch parsing error in project '%s'"), prj.wx_str()));
2480  else
2481  CCLogger::Get()->DebugLog(F(_("NativeParser::OnParserStart(): %s in project '%s'"), event.GetString().wx_str(), prj.wx_str()));
2482  return;
2483 
2484  default:
2485  break;
2486  }
2487 
2488  event.Skip();
2489 
2490  TRACE(_T("NativeParser::OnParserStart(): Leave"));
2491 }
2492 
2494 {
2495  TRACE(_T("NativeParser::OnParserEnd(): Enter"));
2496 
2497  ParserBase* parser = reinterpret_cast<ParserBase*>(event.GetEventObject());
2498  cbProject* project = static_cast<cbProject*>(event.GetClientData());
2499  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
2500  const ParserCommon::ParserState state = static_cast<ParserCommon::ParserState>(event.GetInt());
2501 
2502  switch (state)
2503  {
2505  {
2506  wxString log(F(_("NativeParser::OnParserEnd(): Project '%s' parsing stage done!"), prj.wx_str()));
2507  CCLogger::Get()->Log(log);
2508  CCLogger::Get()->DebugLog(log);
2509  }
2510  break;
2511 
2513  break;
2514 
2516  if (parser != m_Parser)
2517  {
2518  std::pair<cbProject*, ParserBase*> info = GetParserInfoByCurrentEditor();
2519  if (info.second && info.second != m_Parser)
2520  {
2521  CCLogger::Get()->DebugLog(_T("NativeParser::OnParserEnd(): Start switch from OnParserEnd::ptReparseFile"));
2522  SwitchParser(info.first, info.second); // Calls SetParser() which also calls UpdateClassBrowserView()
2523  }
2524  }
2525  break;
2526 
2528  CCLogger::Get()->DebugLog(F(_T("NativeParser::OnParserEnd(): Parser event handling error of project '%s'"), prj.wx_str()));
2529  return;
2530 
2531  default:
2532  break;
2533  }
2534 
2535  if (!event.GetString().IsEmpty())
2536  CCLogger::Get()->DebugLog(event.GetString());
2537 
2539 
2540  // In this case, the parser will record all the cbprojects' token, so this will start parsing
2541  // the next cbproject.
2542  TRACE(_T("NativeParser::OnParserEnd(): Starting m_TimerParsingOneByOne."));
2544 
2545  // both NativeParser and CodeCompletion class need to handle this event
2546  event.Skip();
2547  TRACE(_T("NativeParser::OnParserEnd(): Leave"));
2548 }
2549 
2551 {
2552  TRACE(_T("NativeParser::OnParsingOneByOneTimer(): Enter"));
2553 
2554  std::pair<cbProject*, ParserBase*> info = GetParserInfoByCurrentEditor();
2556  {
2557  // If there is no parser and an active editor file can be obtained, parse the file according the active project
2558  if (!info.second && Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor())
2559  {
2560  // NOTE (Morten#1#): Shouldn't this actually be a temp parser??? I think this screws things with re-opening files on load of a projects...
2561  AddProjectToParser(info.first);
2562  CCLogger::Get()->DebugLog(_T("NativeParser::OnParsingOneByOneTimer(): Add foreign active editor to current active project's parser."));
2563  }
2564  // Otherwise, there is a parser already present
2565  else
2566  {
2567  // First: try to parse the active project (if any)
2568  cbProject* activeProject = Manager::Get()->GetProjectManager()->GetActiveProject();
2569  if (m_ParsedProjects.find(activeProject) == m_ParsedProjects.end())
2570  {
2571  AddProjectToParser(activeProject);
2572  CCLogger::Get()->DebugLog(_T("NativeParser::OnParsingOneByOneTimer(): Add new (un-parsed) active project to parser."));
2573  }
2574  // Else: add remaining projects one-by-one (if any)
2575  else
2576  {
2577  ProjectsArray* projs = Manager::Get()->GetProjectManager()->GetProjects();
2578  // loop on the whole workspace, and only add a new project to the parser
2579  // here the "new" means a project haven't been parsed. Once it was parsed, it is
2580  // added to the m_ParsedProjects
2581  for (size_t i = 0; i < projs->GetCount(); ++i)
2582  {
2583  // Only add, if the project is not already parsed
2584  if (m_ParsedProjects.find(projs->Item(i)) == m_ParsedProjects.end())
2585  {
2586  // AddProjectToParser return true means there are something need to parse, otherwise, it is false
2587  if (!AddProjectToParser(projs->Item(i)))
2588  {
2589  CCLogger::Get()->Log(_T("NativeParser::OnParsingOneByOneTimer(): nothing need to parse in this project, try next project."));
2590  continue;
2591  }
2592 
2593  CCLogger::Get()->DebugLog(_T("NativeParser::OnParsingOneByOneTimer(): Add additional (next) project to parser."));
2594  break;
2595  }
2596  }
2597  }
2598  }
2599  }
2600  else if (info.first && !info.second)
2601  {
2602  info.second = CreateParser(info.first);
2603  if (info.second && info.second != m_Parser)
2604  {
2605  CCLogger::Get()->DebugLog(_T("NativeParser::OnParsingOneByOneTimer(): Start switch from OnParsingOneByOneTimer"));
2606  SwitchParser(info.first, info.second); // Calls SetParser() which also calls UpdateClassBrowserView()
2607  }
2608  }
2609  TRACE(_T("NativeParser::OnParsingOneByOneTimer(): Leave"));
2610 }
2611 
2613 {
2614  cbEditor* curEditor = Manager::Get()->GetEditorManager()->GetBuiltinEditor(editor);
2615  if (!curEditor)
2616  return;
2617 
2618  const wxString& activatedFile = editor->GetFilename();
2619  if ( !wxFile::Exists(activatedFile) )
2620  return;
2621 
2622  cbProject* project = GetProjectByEditor(curEditor);
2623  const int pos = m_StandaloneFiles.Index(activatedFile);
2624  if (project && pos != wxNOT_FOUND)
2625  {
2627  if (m_StandaloneFiles.IsEmpty())
2628  DeleteParser(NULL);
2629  else
2630  RemoveFileFromParser(NULL, activatedFile);
2631  }
2632 
2633  ParserBase* parser = GetParserByProject(project);
2634  if (!parser)
2635  {
2636  ParserCommon::EFileType ft = ParserCommon::FileType(activatedFile);
2637  if (ft != ParserCommon::ftOther && (parser = CreateParser(project)))
2638  {
2639  if (!project && AddFileToParser(project, activatedFile, parser) )
2640  {
2641  wxFileName file(activatedFile);
2642  parser->AddIncludeDir(file.GetPath());
2643  m_StandaloneFiles.Add(activatedFile);
2644  }
2645  }
2646  else
2647  parser = m_TempParser; // do *not* instead by SetParser(m_TempParser)
2648  }
2649  else if (!project)
2650  {
2651  if ( !parser->IsFileParsed(activatedFile)
2652  && m_StandaloneFiles.Index(activatedFile) == wxNOT_FOUND
2653  && AddFileToParser(project, activatedFile, parser) )
2654  {
2655  wxFileName file(activatedFile);
2656  parser->AddIncludeDir(file.GetPath());
2657  m_StandaloneFiles.Add(activatedFile);
2658  }
2659  }
2660 
2661  if (parser != m_Parser)
2662  {
2663  CCLogger::Get()->DebugLog(_T("Start switch from OnEditorActivatedTimer"));
2664  SwitchParser(project, parser); // Calls SetParser() which also calls UpdateClassBrowserView()
2665  }
2666 
2667  if (m_ClassBrowser)
2668  {
2670  m_ClassBrowser->UpdateClassBrowserView(true); // check header and implementation file swap
2671  else if ( m_ParserPerWorkspace // project view only available in case of one parser per WS
2674  }
2675 }
2676 
2678 {
2679  // the caller of the function should guarantee its a built-in editor
2680  wxString filename = editor->GetFilename();
2681  const int pos = m_StandaloneFiles.Index(filename);
2682  if (pos != wxNOT_FOUND)
2683  {
2685  if (m_StandaloneFiles.IsEmpty())
2686  DeleteParser(NULL);
2687  else
2688  RemoveFileFromParser(NULL, filename);
2689  }
2690 }
2691 
2693 {
2694  m_LastControl = nullptr;
2695  m_LastFunctionIndex = -1;
2696  m_LastLine = -1;
2697  m_LastResult = -1;
2698  m_LastFile.Clear();
2700  m_LastPROC.Clear();
2701 
2702  Reset();
2703 }
2704 
2706 {
2707  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
2708  ParserBase* parser = GetParserByProject(project);
2709  if (parser)
2710  return false;
2711 
2712  if (m_ParsedProjects.empty())
2713  return false;
2714 
2715  m_ParsedProjects.insert(project);
2716  parser = GetParserByProject(project);
2717  if (!parser)
2718  return false;
2719  else if (!parser->UpdateParsingProject(project))
2720  {
2721  m_ParsedProjects.erase(project);
2722  return false;
2723  }
2724 
2725  // TODO (ollydbg#1#) did exactly the same thing as the function NativeParser::DoFullParsing()?
2726  wxString log(F(_("NativeParser::AddProjectToParser(): Add project (%s) to parser"), prj.wx_str()));
2727  CCLogger::Get()->Log(log);
2728  CCLogger::Get()->DebugLog(log);
2729 
2730  bool needParseMacros = false;
2731 
2732  if (!AddCompilerDirs(project, parser))
2733  CCLogger::Get()->DebugLog(_T("NativeParser::AddProjectToParser(): AddCompilerDirs failed!"));
2734 
2735  if (!AddCompilerPredefinedMacros(project, parser))
2736  CCLogger::Get()->DebugLog(_T("NativeParser::AddProjectToParser(): AddCompilerPredefinedMacros failed!"));
2737  else
2738  needParseMacros = true;
2739 
2740  if (!AddProjectDefinedMacros(project, parser))
2741  CCLogger::Get()->DebugLog(_T("NativeParser::AddProjectToParser(): AddProjectDefinedMacros failed!"));
2742  else
2743  {
2744  if(!needParseMacros)
2745  needParseMacros = true;
2746  }
2747 
2748  if (project)
2749  {
2750  size_t fileCount = 0;
2751  for (FilesList::const_iterator fl_it = project->GetFilesList().begin(); fl_it != project->GetFilesList().end(); ++fl_it)
2752  {
2753  ProjectFile* pf = *fl_it;
2754  if (pf && FileTypeOf(pf->relativeFilename) == ftHeader)
2755  {
2756  if ( AddFileToParser(project, pf->file.GetFullPath(), parser) )
2757  ++fileCount;
2758  }
2759  }
2760  for (FilesList::const_iterator fl_it = project->GetFilesList().begin(); fl_it != project->GetFilesList().end(); ++fl_it)
2761  {
2762  ProjectFile* pf = *fl_it;
2764  {
2765  if ( AddFileToParser(project, pf->file.GetFullPath(), parser) )
2766  fileCount++;
2767  }
2768  }
2769 
2770  CCLogger::Get()->DebugLog(F(_("NativeParser::AddProjectToParser(): Done adding %lu files of project (%s) to parser."), static_cast<unsigned long>(fileCount), prj.wx_str()));
2771 
2772  // in some cases, all the files were already be parsed, so fileCount is still 0
2773  return ((fileCount>0) || needParseMacros);
2774  }
2775  else
2776  {
2778  if (editor && AddFileToParser(project, editor->GetFilename(), parser))
2779  {
2780  wxFileName file(editor->GetFilename());
2781  parser->AddIncludeDir(file.GetPath());
2782  m_StandaloneFiles.Add(editor->GetFilename());
2783 
2784  CCLogger::Get()->DebugLog(F(_("NativeParser::AddProjectToParser(): Done adding stand-alone file (%s) of editor to parser."), editor->GetFilename().wx_str()));
2785  return true;
2786  }
2787  }
2788  return false;
2789 }
2790 
2792 {
2793  ParserBase* parser = GetParserByProject(project);
2794  if (!parser)
2795  return false;
2796 
2797  // Remove from the cbProject set
2798  m_ParsedProjects.erase(project);
2799 
2800  if (!project || m_ParsedProjects.empty())
2801  return true;
2802 
2803  wxString prj = (project ? project->GetTitle() : _T("*NONE*"));
2804  wxString log(F(_("Remove project (%s) from parser"), prj.wx_str()));
2805  CCLogger::Get()->Log(log);
2806  CCLogger::Get()->DebugLog(log);
2807 
2808  for (FilesList::const_iterator fl_it = project->GetFilesList().begin(); fl_it != project->GetFilesList().end(); ++fl_it)
2809  {
2810  ProjectFile* pf = *fl_it;
2812  RemoveFileFromParser(project, pf->file.GetFullPath());
2813  }
2814 
2815  return true;
2816 }
ProjectFile * GetFileByFilename(const wxString &filename, bool isRelative=true, bool isUnixFilename=false)
Access a file of the project.
Definition: cbproject.cpp:1049
wxString name
Dock&#39;s name. Must be unique. If empty, a unique name will be assigned.
Definition: sdk_events.h:135
bool ParseLocalBlock(ccSearchData *searchData, TokenIdxSet &search_scope, int caretPos=-1)
parses from the start of function up to the cursor, this is used to collect local variables...
#define PARSER_IMG_NAMESPACE
Definition: parser.h:49
wxString F(const wxChar *msg,...)
sprintf-like function
Definition: logmanager.h:20
virtual BrowserOptions & ClassBrowserOptions()
Definition: parser_base.h:175
size_t GenerateResultSet(TokenTree *tree, const wxString &target, int parentIdx, TokenIdxSet &result, bool caseSens=true, bool isPrefix=false, short int kindMask=0xFFFF)
Generate the matching results under the Parent Token index set.
Search location combination, a pointer to cbStyledTextCtrl and a filename is enough.
Definition: nativeparser.h:36
#define PARSER_IMG_CTOR_PRIVATE
Definition: parser.h:31
#define TRACE(format, args...)
destructor class member function
Definition: token.h:51
int TokenExists(const wxString &name, int parent, short int kindMask)
query tokens by names
Definition: tokentree.cpp:141
void SetTokenKindImage(int kind, const wxBitmap &bitmap, const wxBitmap &mask=wxNullBitmap)
Used to support Symbol browser and codecompletion UI Image list is used to initialize the symbol brow...
ParserBase * GetParserByProject(cbProject *project)
return the Parser pointer corresponding to the input C::B project
void AddCompilerIncludeDirsToParser(const Compiler *compiler, ParserBase *parser)
Add compiler include directories (from search paths) to a parser.
wxMutex s_TokenTreeMutex
Definition: tokentree.cpp:49
variable
Definition: token.h:57
BrowserViewMode
Symbol browser tree showing option.
Definition: nativeparser.h:43
namespace
Definition: token.h:34
int m_LastFunctionIndex
Definition: nativeparser.h:499
bool AddPage(wxWindow *page, const wxString &caption, bool select=false, const wxBitmap &bitmap=wxNullBitmap)
Add Page.
Definition: cbauibook.cpp:561
int m_ParentIndex
Parent Token index.
Definition: token.h:265
#define PARSER_IMG_CTOR_PROTECTED
Definition: parser.h:32
bool Matches(const wxString &mask) const
bool m_ClassBrowserIsFloating
if true, which means m_ClassBrowser is floating (not docked)
Definition: nativeparser.h:476
int WordEndPosition(int pos, bool onlyWordCharacters)
Get position of end of word.
void SetParser(ParserBase *parser)
Set a new Parser as the active Parser Set the active parser pointer (m_Parser member variable) update...
int wxNewId()
#define wxICON_QUESTION
constructor class member function
Definition: token.h:48
bool ParseUsingNamespace(ccSearchData *searchData, TokenIdxSet &search_scope, int caretPos=-1)
collect the using namespace directive in the editor specified by searchData
class or struct
Definition: token.h:37
wxArrayString GetAllPathsByFilename(const wxString &filename)
Get the implementation file path if the input is a header file.
size_t ResolveExpression(TokenTree *tree, std::queue< ParserComponent > components, const TokenIdxSet &searchScope, TokenIdxSet &result, bool caseSense=true, bool isPrefix=false)
A statement(expression) is expressed by a ParserComponent queue We do a match from the left of the qu...
void UpdateSash()
update the position sash bar between top tree and the bottom tree, the position (percentage) of the t...
int idTimerParsingOneByOne
event id for the sequence project parsing timer
Setting of the Parser, some of them will be passed down to ParserThreadOptions.
Definition: parser_base.h:97
virtual const wxString & GetMasterPath() const
Get the compiler&#39;s master path (must contain "bin", "include" and "lib")
Definition: compiler.h:295
ParserBase * GetParserByFilename(const wxString &filename)
return the Parser pointer associated with the input file If a file belongs to several Parser objects...
wxString relativeFilename
The relative (to the project) filename of this file.
Definition: projectfile.h:131
wxString title
Dock&#39;s title.
Definition: sdk_events.h:136
Token * at(int idx)
Definition: tokentree.h:51
ProjectSearchDirsMap m_ProjectSearchDirsMap
a map: project pointer -> C/C++ parser search paths for this project, this is the per-project code co...
Definition: nativeparser.h:481
bool wxIsspace(const wxUniChar &c)
void Delete(std::vector< T > &s)
Definition: safedelete.h:20
#define PARSER_IMG_NONE
Definition: parser.h:25
bool ReparseFile(cbProject *project, const wxString &filename)
Single file re-parse.
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
int ReadInt(const wxString &name, int defaultVal=0)
static CCLogger * Get()
Definition: cclogger.cpp:60
wxString file
Definition: nativeparser.h:39
bool IsOk() const
virtual bool SupportsCurrentPlatform() const
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
void Log(const wxString &msg)
Definition: cclogger.cpp:90
bool IsComment(int style)
Is style classified as comment for current language?
wxString m_Name
Token&#39;s name, it can be searched in the TokenTree.
Definition: token.h:188
ClassBrowser * m_ClassBrowser
symbol browser window
Definition: nativeparser.h:474
bool IsOpened() const
bool followLocalIncludes
Definition: parser_base.h:111
bool RemovePage(size_t page)
Remove Page.
Definition: cbauibook.cpp:534
#define PARSER_IMG_MACRO_DEF
Definition: parser.h:43
unsigned int m_ImplLine
function implementation line index
Definition: token.h:219
void Clear()
Definition: tokentree.h:86
std::pair< cbProject *, ParserBase * > GetParserInfoByCurrentEditor()
Get cbProject and Parser pointer, according to the current active editor.
void ReparseSelectedProject()
re-parse the project select by context menu in projects management panel
typedef, note typedefs are stored as classes inheriting from the typedef&#39;d type, this takes advantage...
Definition: token.h:45
static bool IsAppShuttingDown()
Definition: manager.cpp:333
#define PARSER_IMG_ENUM_PUBLIC
Definition: parser.h:47
cbStyledTextCtrl * control
Definition: nativeparser.h:38
#define PARSER_IMG_TYPEDEF
Definition: parser.h:50
const wxArrayString & GetGCCCompilerDirs(const wxString &cpp_compiler)
Collect the default compiler include file search paths.
#define PARSER_IMG_FUNC_PROTECTED
Definition: parser.h:38
DLLIMPORT wxBitmap cbLoadBitmap(const wxString &filename, wxBitmapType bitmapType=wxBITMAP_TYPE_PNG)
This function loads a bitmap from disk.
Definition: globals.cpp:1102
container like tokens, those tokens can have children tokens
Definition: token.h:70
virtual FilesList & GetFilesList()
Provides an easy way to iterate all the files belonging in this target.
Definition: cbproject.h:685
bool wxFileExists(const wxString &filename)
wxWindow * pWindow
The window to dock.
Definition: sdk_events.h:137
wxFileName file
The full filename of this file.
Definition: projectfile.h:126
static Compiler * GetDefaultCompiler()
void UpdateClassBrowser()
update the class browser tree
void SetVolume(const wxString &volume)
wxDirTraverseResult OnFile(const wxString &filename) override
#define PARSER_IMG_MACRO_USE_PUBLIC
Definition: parser.h:64
EVTIMPORT const wxEventType cbEVT_ADD_DOCK_WINDOW
Definition: sdk_events.cpp:129
void CleanupSearchScope(TokenTree *tree, TokenIdxSet *searchScope)
remove all the container tokens in the token index set.
bool ReadBool(const wxString &name, bool defaultVal=false)
int Index(const wxString &sz, bool bCase=true, bool bFromEnd=false) const
void OnParsingOneByOneTimer(wxTimerEvent &event)
If use one parser per whole workspace, we need parse all project one by one, E.g. ...
void FindCurrentFunctionScope(TokenTree *tree, const TokenIdxSet &procResult, TokenIdxSet &scopeResult)
if the expression return the container tokens, which are the parent of the expression.
wxString m_LastAIGlobalSearch
same case like above, it holds the search string
Definition: nativeparser.h:495
bool ParseBufferForUsingNamespace(const wxString &buffer, TokenIdxSet &search_scope, bool bufferSkipBlocks=true)
collect the using namespace directive in the buffer specified by searchData
DLLIMPORT bool NormalizePath(wxFileName &f, const wxString &base)
Definition: globals.cpp:942
virtual bool AddFile(cb_unused const wxString &filename, cb_unused cbProject *project, cb_unused bool isLocal=true)
Definition: parser_base.h:146
void AddIncludeDirsToParser(const wxArrayString &dirs, const wxString &base, ParserBase *parser)
Add a list of directories to the parser&#39;s search directories, normalise to "base" path...
size_t BreakUpComponents(const wxString &actual, std::queue< ParserComponent > &components)
break a statement to several ParserComponents, and store them in a queue.
size_t Length() const
#define PARSER_IMG_MACRO_USE
Definition: parser.h:61
a container class to hold all the Tokens getting from parsing stage
Definition: tokentree.h:37
Event used to request from the main app to add a window to the docking system.
Definition: sdk_events.h:83
bool showInheritance
whether the base class or derive class information is shown as a child node default: false ...
Definition: parser_base.h:72
wxString CPP
Definition: compiler.h:200
virtual const wxArrayString & GetCompilerOptions() const
unsigned int m_ImplLineStart
if token is impl, opening brace line
Definition: token.h:222
bool Done()
Return true if all the parser&#39;s batch-parse stages are finished, otherwise return false...
static Compiler * GetCompiler(size_t index)
bool platformCheck
this will let the Tokenizer to recursive expand macros
Definition: parser_base.h:118
void UpdateClassBrowserView(bool checkHeaderSwap=false)
update or refresh the symbol browser trees
#define _T(string)
static const wxString & GetDefaultCompilerID()
#define PARSER_IMG_CTOR_PUBLIC
Definition: parser.h:33
wxSize minimumSize
The minimum allowed size.
Definition: sdk_events.h:140
int m_LastFuncTokenIdx
saved the function token&#39;s index, for remove all local variable
Definition: nativeparser.h:500
wxString BeforeLast(wxUniChar ch, wxString *rest=NULL) const
size_t size()
total size of std::vector<Token*>
Definition: tokentree.cpp:98
int m_Index
current Token index in the tree, it is index of the std::vector<Token*>, so use the index...
Definition: token.h:262
#define wxYES_NO
cbProject * GetProjectByEditor(cbEditor *editor)
return the C::B project containing the cbEditor pointer
int FindCurrentFunctionStart(ccSearchData *searchData, wxString *nameSpace=0L, wxString *procName=0L, int *functionIndex=0L, int caretPos=-1)
returns the position where the current function scope starts.
cbProjectManagerUI & GetUI()
std::list< wxString > StringList
Definition: parser_base.h:20
unsigned int m_ImplLineEnd
if token is impl, closing brace line
Definition: token.h:225
size_t FindAIMatches(TokenTree *tree, std::queue< ParserComponent > components, TokenIdxSet &result, int parentTokenIdx=-1, bool isPrefix=false, bool caseSensitive=false, bool use_inheritance=true, short int kindMask=0xFFFF, TokenIdxSet *search_scope=0)
Artificial Intelligence Matching.
void OnEditorActivated(EditorBase *editor)
Event handler when an editor activate, NONE project is handled here.
#define PARSER_IMG_DTOR_PROTECTED
Definition: parser.h:35
DLLIMPORT FileType FileTypeOf(const wxString &filename)
Definition: globals.cpp:285
virtual bool RemoveFile(cb_unused const wxString &filename)
Definition: parser_base.h:147
int idParserStart
Definition: parser.cpp:93
virtual wxTreeItemData * GetItemData(const wxTreeItemId &item) const
wxString GetNamespace() const
get a literal string presentation of the namespace.
Definition: token.cpp:253
virtual ParserOptions & Options()
Definition: parser_base.h:174
wxString & Remove(size_t pos)
DLLIMPORT HookFunctorBase * UnregisterHook(int id, bool deleteHook=true)
Unregister a previously registered project loading/saving hook.
wxString GetName() const
#define PARSER_IMG_FUNC_PRIVATE
Definition: parser.h:37
bool RemoveFileFromParser(cbProject *project, const wxString &filename)
remove a file from C::B project and Parser
#define PARSER_IMG_MACRO_USE_PRIVATE
Definition: parser.h:62
cbProject * GetCurrentProject()
Get current project by active editor or just return active project.
#define wxT(string)
bool m_IsTemp
local (automatic) variable
Definition: token.h:245
TokenScope m_Scope
public? private? protected?
Definition: token.h:231
virtual bool Start(int milliseconds=-1, bool oneShot=wxTIMER_CONTINUOUS)
#define wxNOT_FOUND
void SetPath(const wxString &path, wxPathFormat format=wxPATH_NATIVE)
wxString DisplayName() const
a short simple string to show the token information, this usually generate for show the tip message w...
Definition: token.cpp:80
#define PARSER_IMG_CLASS_PRIVATE
Definition: parser.h:28
Represents a file in a Code::Blocks project.
Definition: projectfile.h:39
DockSide dockSide
The side to dock it.
Definition: sdk_events.h:142
TokenTree * GetTempTokenTree()
Definition: parser_base.h:154
wxSize floatingSize
The desired floating size.
Definition: sdk_events.h:139
EFileType FileType(const wxString &filename, bool force_refresh=false)
return a file type, which can be either header files or implementation files or other files ...
void DebugLog(const wxString &msg)
Definition: cclogger.cpp:107
int GetLineEndPosition(int line) const
Get the position after the last visible characters on a line.
bool AddCompilerDirs(cbProject *project, ParserBase *parser)
collect the header file search directories, those dirs include: 1, project&#39;s base dir...
int GetTokenFromCurrentLine(TokenTree *tree, const TokenIdxSet &tokens, size_t curLine, const wxString &file)
used to get the correct token index in current line, e.g.
void Reset()
Init cc search member variables.
void RemoveClassBrowser(bool appShutDown=false)
remove the class browser
void Set(int width, int height)
int WordStartPosition(int pos, bool onlyWordCharacters)
Get position of start of word.
EditorManager * GetEditorManager() const
Definition: manager.cpp:434
DLLIMPORT const wxWX2MBbuf cbU2C(const wxString &str)
Return multibyte (C string) representation of the string.
Definition: globals.cpp:743
#define PARSER_IMG_VAR_PROTECTED
Definition: parser.h:41
void ClearParsers()
Clear all Parser object.
EVTIMPORT const wxEventType cbEVT_REMOVE_DOCK_WINDOW
Definition: sdk_events.cpp:130
size_t MarkItemsByAI(ccSearchData *searchData, TokenIdxSet &result, bool reallyUseAI=true, bool isPrefix=true, bool caseSensitive=false, int caretPos=-1)
collect tokens where a code suggestion list can be shown
cbProject * GetProjectByParser(ParserBase *parser)
return the C::B project associated with Parser pointer
wxUSE_UNICODE_dependent wxChar
#define PARSER_IMG_ENUM
Definition: parser.h:44
size_t Traverse(wxDirTraverser &sink, const wxString &filespec=wxEmptyString, int flags=wxDIR_DEFAULT) const
ProjectManager * GetProjectManager() const
Functions returning pointers to the respective sub-manager instances.
Definition: manager.cpp:429
#define PARSER_IMG_MAX
Definition: parser.h:68
const wxString & GetID() const
Get this compiler&#39;s unique ID.
Definition: compiler.h:351
bool AddProjectToParser(cbProject *project)
Add one project to the common parser in one parser for the whole workspace mode.
void RemoveLastFunctionChildren(TokenTree *tree, int &lastFuncTokenIdx)
Remove the last function&#39;s children, when doing codecompletion in a function body, the function body up to the caret position was parsed, and the local variables defined in the function were recorded as the function&#39;s children.
void OnParserEnd(wxCommandEvent &event)
Event handler when the batch parse finishes, print some log information, check whether the active edi...
bool Contains(const wxString &str) const
bool m_LastAISearchWasGlobal
true if the phrase for code-completion is empty or partial text (i.e. no . -> or :: operators) ...
Definition: nativeparser.h:496
virtual bool Reparse(cb_unused const wxString &filename, cb_unused bool isLocal=true)
virtual const wxString & GetFilename() const
Get the editor&#39;s filename (if applicable).
Definition: editorbase.h:45
DLLIMPORT wxString UnixFilename(const wxString &filename, wxPathFormat format=wxPATH_NATIVE)
Definition: globals.cpp:228
wxString GetExt() const
bool AppendDir(const wxString &dir)
Represents a Code::Blocks project.
Definition: cbproject.h:96
const wxString & GetActiveBuildTarget() const
Definition: cbproject.cpp:1373
EditorBase * GetActiveEditor()
#define PARSER_IMG_DTOR_PUBLIC
Definition: parser.h:36
a symbol found in the parsed files, it can be many kinds, such as a variable, a class and so on...
Definition: token.h:82
wxString m_LastNamespace
Definition: nativeparser.h:502
wxString & RemoveLast(size_t n=1)
null_pointer_t nullptr
Definition: nullptr.cpp:16
cbStyledTextCtrl * GetControl() const
Returns a pointer to the underlying cbStyledTextCtrl object (which itself is the wxWindows implementa...
Definition: cbeditor.cpp:842
std::set< int, std::less< int > > TokenIdxSet
Definition: token.h:16
wxArrayString m_StandaloneFiles
all the files which opened, but does not belong to any cbp
Definition: nativeparser.h:486
display symbols of current file
Definition: parser_base.h:43
bool m_ParserPerWorkspace
if true, which means the parser hold tokens of the whole workspace&#39;s project, if false then one parse...
Definition: nativeparser.h:490
DLLIMPORT wxString cbC2U(const char *str)
Return str as a proper unicode-compatible string.
Definition: globals.cpp:733
virtual const wxString & GetTitle() const
Read the target&#39;s title.
wxImageList * m_ImageList
Images for class browser.
Definition: nativeparser.h:483
virtual void AddPredefinedMacros(cb_unused const wxString &defs)
Definition: parser_base.h:134
bool ParseFunctionArguments(ccSearchData *searchData, int caretPos=-1)
collect function argument, add them to the token tree (as temporary tokens)
#define PARSER_IMG_CLASS_PUBLIC
Definition: parser.h:30
wxString GetCompilerStandardGCC(Compiler *compiler, cbProject *project)
lookup GCC compiler -std=XXX option
virtual void AddBatchParse(cb_unused const StringList &filenames)
Definition: parser_base.h:132
size_t Replace(const wxString &strOld, const wxString &strNew, bool replaceAll=true)
size_t FindTokensInFile(const wxString &filename, TokenIdxSet &result, short int kindMask)
EFileType
the enum type of the file type
Definition: parser_base.h:25
~NativeParser()
Destructor.
wxString GetVolume() const
bool GetModify() const
Is the document different from when it was last saved?
cbEditor * GetBuiltinActiveEditor()
Definition: editormanager.h:95
size_t AI(TokenIdxSet &result, ccSearchData *searchData, const wxString &lineText=wxEmptyString, bool isPrefix=false, bool caseSensitive=false, TokenIdxSet *search_scope=0, int caretPos=-1)
Start an Artificial Intelligence search algorithm to gather all the matching tokens.
virtual bool IsFileParsed(cb_unused const wxString &filename)
Definition: parser_base.h:148
bool IsSameAs(const wxString &s, bool caseSensitive=true) const
#define PARSER_IMG_CLASS
Definition: parser.h:27
void OnEditorClosed(EditorBase *editor)
Event handler when an editor closed, if it is the last editor belong to NONE project, then the NONE Parser will be removed.
bool IsCharacter(int style)
Is style classified as character for current language?
virtual wxString NotDoneReason()
Definition: parser_base.h:151
virtual cbTreeCtrl * GetTree()=0
Retrieve a pointer to the project manager&#39;s tree (GUI).
virtual const CompilerPrograms & GetPrograms() const
Get the compiler&#39;s programs.
Definition: compiler.h:299
Base class that all "editors" should inherit from.
Definition: editorbase.h:30
int GetCurrentPos() const
Returns the position of the caret.
cbProject * GetActiveProject()
Retrieve the active project.
bool IsString(int style)
Is style classified as string for current language?
bool Replace(int index, const wxBitmap &bitmap, const wxBitmap &mask=wxNullBitmap)
int GetLength() const
Returns the number of bytes in the document.
virtual wxString GetBasePath() const
Read the target&#39;s base path, e.g. if GetFilename() returns "/usr/local/bin/xxx", base path will retur...
bool IsEmpty() const
DLLIMPORT int RegisterHook(HookFunctorBase *functor)
Register a project loading/saving hook.
bool wantPreprocessor
case sensitive in MarkItemsByAI
Definition: parser_base.h:114
NativeParser()
Constructor.
static void AddPaths(wxArrayString &dirs, const wxString &path, bool hasExt)
Add the paths to path array, and this will be used in GetAllPathsByFilename() function.
#define PARSER_IMG_TYPEDEF_PUBLIC
Definition: parser.h:53
wxEventType wxEVT_TIMER
#define CC_LOCKER_TRACK_TT_MTX_UNLOCK(M)
Definition: cclogger.h:165
const wxStringCharType * wx_str() const
void ReparseCurrentProject()
re-parse the active Parser (the project associated with m_Parser member variable
void AddIncludeDir(const wxString &dir)
add a directory to the Parser&#39;s include path database
#define wxTIMER_ONE_SHOT
wxString GetTextRange(int startPos, int endPos)
Retrieve a range of text.
wxString wxEmptyString
#define PARSER_IMG_CLASS_PROTECTED
Definition: parser.h:29
wxString Right(size_t count) const
bool s_DebugSmartSense
if this option is enabled, there will be many log messages when doing semantic match ...
ParserBase * CreateParser(cbProject *project)
Dynamically allocate a Parser object for the input C::B project, note that while create a new Parser ...
wxTimer m_TimerParsingOneByOne
a delay timer to parser every project in sequence
Definition: nativeparser.h:472
symbol browser panel is shown in the Management panel besides projects browser panel.
Definition: classbrowser.h:53
MacrosManager * GetMacrosManager() const
Definition: manager.cpp:454
void ComputeCallTip(TokenTree *tree, const TokenIdxSet &tokens, wxArrayString &items)
call tips are tips when you are entering some functions, such as you have a class definition ...
const wxString & _(const wxString &string)
wxString GetCompilerUsingStandardGCC(const wxArrayString &compilerOptions)
lookup GCC compiler -std=XXX option for specific GCC options
wxDirTraverseResult
wxString & Trim(bool fromRight=true)
void ReplaceMacros(wxString &buffer, ProjectBuildTarget *target=nullptr, bool subrequest=false)
cbEditor * GetBuiltinEditor(EditorBase *eb)
wxString m_Args
If it is a function Token, then this value is function arguments, e.g.
Definition: token.h:194
cbStyledTextCtrl * m_LastControl
Definition: nativeparser.h:497
void InitCCSearchVariables()
Init cc search member variables.
int GetBuildTargetsCount()
Definition: cbproject.h:200
bool followGlobalIncludes
parse XXX.h in directive #include "XXX.h"
Definition: parser_base.h:112
#define CC_LOCKER_TRACK_TT_MTX_LOCK(M)
Definition: cclogger.h:159
virtual const wxArrayString & GetIncludeDirs() const
cbProject * GetProjectByFilename(const wxString &filename)
return the C::B project containing the filename The function first try to match the filename in the a...
bool SwitchParser(cbProject *project, ParserBase *parser)
Switch parser object according the current active editor and filename.
void RereadParserOptions()
when user changes the CC option, we should re-read the option
int BraceMatch(int pos, int maxReStyle=0)
Find the position of a matching brace or wxSCI_INVALID_POSITION if no match.
int PositionFromLine(int line) const
Retrieve the position at the start of a line.
static wxString GetDataFolder(bool global=true)
wxArrayString GetExpandedVirtualBuildTargetGroup(const wxString &alias) const
Access a virtual build target&#39;s expanded group of build targets.
Definition: cbproject.cpp:1507
ProjectBuildTarget * GetBuildTarget(int index)
Access a build target.
Definition: cbproject.cpp:1392
static bool Exists(const wxString &filename)
Abstract base class for compilers.
Definition: compiler.h:274
undefined or just "all"
Definition: token.h:76
BrowserDisplayFilter displayFilter
token filter option
Definition: parser_base.h:88
int GetPageIndex(wxWindow *page_wnd) const
virtual bool Done()
Definition: parser_base.h:150
enum
Definition: token.h:40
bool AddFileToParser(cbProject *project, const wxString &filename, ParserBase *parser=nullptr)
New file was added to the C::B project, so this will cause a re-parse on the new added file...
#define PARSER_IMG_VAR_PRIVATE
Definition: parser.h:40
A file editor.
Definition: cbeditor.h:43
std::set< cbProject * > m_ParsedProjects
only used when m_ParserPerWorkspace is true, and holds all the cbps for the common parser ...
Definition: nativeparser.h:492
#define PARSER_IMG_ENUMERATOR
Definition: parser.h:48
bool hideable
If true, the dock will be allowed to be closed by the user.
Definition: sdk_events.h:147
bool IsEmpty() const
int GetCharAt(int pos) const
Returns the character byte at the position.
void Clear()
cbProject * GetProject() const
Definition: cbproject.h:59
wxString GetPath(int flags=wxPATH_GET_VOLUME, wxPathFormat format=wxPATH_NATIVE) const
virtual const wxString & GetCompilerID() const
Read the target&#39;s compiler.
enumerator
Definition: token.h:60
ParserBase * m_TempParser
a temp parser object pointer
Definition: nativeparser.h:467
bool HasExt() const
non of the above three status, this means our Parser has finish all the jobs, and it is in idle mode ...
Definition: parser.h:104
any kind of functions
Definition: token.h:73
void OnParserStart(wxCommandEvent &event)
Event handler when the batch parse starts, print some log information.
wxString C
Definition: compiler.h:199
some files are changed by the user, so we are parsing the changed files
Definition: parser.h:96
FileTreeDataKind GetKind() const
Definition: cbproject.h:58
#define wxSCI_INVALID_POSITION
Definition: wxscintilla.h:70
virtual cbAuiNotebook * GetNotebook()=0
TokenKind m_TokenKind
See TokenKind class.
Definition: token.h:234
void SetCBViewMode(const BrowserViewMode &mode)
set the class browser view mode
bool ProcessEvent(CodeBlocksEvent &event)
Definition: manager.cpp:246
wxString GetCommonTopLevelPath() const
Definition: cbproject.cpp:423
wxString m_LastPROC
Definition: nativeparser.h:503
wxString m_LastFile
Definition: nativeparser.h:498
wxDirTraverseResult OnDir(const wxString &dirname) override
virtual bool ParseBufferForUsingNamespace(cb_unused const wxString &buffer, cb_unused wxArrayString &result, cb_unused bool bufferSkipBlocks=true)
Definition: parser_base.h:142
wxString & Prepend(const wxString &str)
general function, not constructor nor destructor
Definition: token.h:54
#define PARSER_IMG_FUNC_PUBLIC
Definition: parser.h:39
int GetStyleAt(int pos) const
Returns the style byte at the position.
bool parseComplexMacros
reparse the active editor while editing
Definition: parser_base.h:117
a long statement can be divided to a ParserComponent chain.
size_t Add(const wxString &str, size_t copies=1)
cbProject * GetParentProject()
Definition: projectfile.h:93
ParserBase * m_Parser
active parser object pointer
Definition: nativeparser.h:469
bool StartsWith(const wxString &prefix, wxString *rest=NULL) const
size_t FindCurrentFunctionToken(ccSearchData *searchData, TokenIdxSet &result, int caretPos=-1)
return all the tokens matching the current function(hopefully, just one)
void CreateClassBrowser()
create the class browser
Represents a Code::Blocks project build target.
int LineFromPosition(int pos) const
Retrieve the line containing a position.
bool Normalize(int flags=wxPATH_NORM_ALL, const wxString &cwd=wxEmptyString, wxPathFormat format=wxPATH_NATIVE)
void Sort(bool reverseOrder=false)
int Add(const wxBitmap &bitmap, const wxBitmap &mask=wxNullBitmap)
bool shown
If true, initially shown.
Definition: sdk_events.h:145
#define PARSER_IMG_TYPEDEF_PROTECTED
Definition: parser.h:52
size_t GetCount() const
int idParserEnd
Definition: parser.cpp:94
int Find(wxUniChar ch, bool fromEnd=false) const
#define PARSER_IMG_DTOR_PRIVATE
Definition: parser.h:34
ProjectFile * GetProjectFile() const
Read the ProjectFile pointer associated with this editor.
Definition: cbeditor.h:123
virtual TokenTree * GetTokenTree() const
bool DoFullParsing(cbProject *project, ParserBase *parser)
When a Parser is created, we need a full parsing stage including: 1, parse the priority header files ...
int GetTokenKindImage(const Token *token)
Returns the image assigned to a specific token for a symbol browser.
ProjectsArray * GetProjects()
Retrieve an array of all the opened projects.
the Parser object is newly created, and we are parsing the predefined macro buffer, the source files, and finally mark the project&#39;s tokens as local
Definition: parser.h:93
bool AddCompilerPredefinedMacros(cbProject *project, ParserBase *parser)
collect compiler specific predefined preprocessor definition, this is usually run a special compiler ...
int m_HookId
project loader hook ID
Definition: nativeparser.h:482
Functor class for use as a project loading/saving hook.
macro definition, such as: #define AAA(x,y) f(x,y), where AAA is a token of tkMacroDef ...
Definition: token.h:63
bool DirExists() const
bool FileExists() const
void OnProjectLoadingHook(cbProject *project, TiXmlElement *elem, bool loading)
Read or Write project&#39; CC options when a C::B project is loading or saving user can set those setting...
void RemoveAt(size_t nIndex, size_t count=1)
the user has add some files to the cbproject, so we are parsing the new added files ...
Definition: parser.h:99
ParserList m_ParserList
a list holing all the cbp->parser pairs, if in one parser per project mode, there are many many pairs...
Definition: nativeparser.h:465
ParserDirTraverser(const wxString &excludePath, wxArrayString &files)
virtual void ReadOptions()
read Parser options from configure file
Definition: parser_base.h:169
#define PARSER_IMG_ENUM_PRIVATE
Definition: parser.h:45
#define PARSER_IMG_ENUM_PROTECTED
Definition: parser.h:46
bool DeleteParser(cbProject *project)
delete the Parser object for the input project
wxSize desiredSize
The desired size.
Definition: sdk_events.h:138
bool AddProjectDefinedMacros(cbProject *project, ParserBase *parser)
collect project (user) defined preprocessor definition, such as for wxWidgets project, the macro may have "#define wxUSE_UNICODE" defined in its project file.
Definition: token.h:26
bool AddCompilerPredefinedMacrosGCC(const wxString &compilerId, cbProject *project, wxString &defs, ParserBase *parser)
collect GCC compiler predefined preprocessor definition
bool RemoveProjectFromParser(cbProject *project)
Remove cbp from the common parser, this only happens in one parser for whole workspace mode when a pa...
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
bool IsParserPerWorkspace() const
Return true if use one Parser per whole workspace.
Definition: nativeparser.h:105
Abstract base hook functor interface.
void AddGCCCompilerDirs(const wxString &masterPath, const wxString &compilerCpp, ParserBase *parser)
Add the collected default GCC compiler include search paths to a parser.
#define NULL
Definition: prefix.cpp:59
#define PARSER_IMG_MACRO_USE_PROTECTED
Definition: parser.h:63
static wxString Format(const wxString &format,...)
#define PARSER_IMG_VAR_PUBLIC
Definition: parser.h:42
wxString & MakeUpper()
wxString Mid(size_t first, size_t nCount=wxString::npos) const
virtual bool UpdateParsingProject(cb_unused cbProject *project)
Definition: parser_base.h:135
void RemoveObsoleteParsers()
Remove all the obsolete Parser object if the number exceeds the limited number (can be set in the CC&#39;...
DLLIMPORT int cbMessageBox(const wxString &message, const wxString &caption=wxEmptyString, int style=wxOK, wxWindow *parent=NULL, int x=-1, int y=-1)
wxMessageBox wrapper.
Definition: globals.cpp:1395
#define PARSER_IMG_TYPEDEF_PRIVATE
Definition: parser.h:51
bool AddCompilerPredefinedMacrosVC(const wxString &compilerId, wxString &defs, ParserBase *parser)
collect VC compiler predefined preprocessor definition
virtual bool ParseBuffer(const wxString &buffer, bool isLocal, bool bufferSkipBlocks=false, bool isTemp=false, const wxString &filename=wxEmptyString, int parentIdx=-1, int initLine=0)
wxArrayString & GetProjectSearchDirs(cbProject *project)
project search path is used for auto completion for #include <>
virtual wxTreeItemId GetTreeSelection()=0
Get the selection of the project manager&#39;s tree (GUI).
long wxExecute(const wxString &command, int flags=wxEXEC_ASYNC, wxProcess *callback=NULL, const wxExecuteEnv *env=NULL)
void SetParser(ParserBase *parser)
Set the Parser object associated with the class browser.
the usage of the macro, for example: AAA(1,2)
Definition: token.h:66
int GetCallTips(wxArrayString &items, int &typedCommas, cbEditor *ed, int pos=wxNOT_FOUND)
Call tips are tips when you are typing function arguments these tips information could be: the protot...
virtual CompilerCommandGenerator * GetCommandGenerator(cbProject *project)
This is to be overridden, if compiler needs to alter the default command line generation.
Definition: compiler.cpp:298
Parser class holds all the tokens of a C::B project.
Definition: parser.h:117