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: 11376 $
6  * $Id: compilererrors.cpp 11376 2018-04-28 15:15:57Z fuscated $
7  * $HeadURL: svn://svn.code.sf.net/p/codeblocks/code/branches/release-20.xx/src/plugins/compilergcc/compilererrors.cpp $
8  */
9 
10 #include "sdk.h"
11 #ifndef CB_PRECOMP
12     #include "cbeditor.h"
13     #include "cbproject.h"
14     #include "editormanager.h"
15     #include "manager.h"
16     #include "projectfile.h"
17     #include "projectmanager.h"
18 #endif
19 #include "compilererrors.h"
20 #include <wx/arrimpl.cpp>
21 
22 WX_DEFINE_OBJARRAY(ErrorsArray);
23 
CompilerErrors()24 CompilerErrors::CompilerErrors()
25     : m_ErrorIndex(-1)
26 {
27     //ctor
28 }
29 
~CompilerErrors()30 CompilerErrors::~CompilerErrors()
31 {
32     //dtor
33 }
34 
AddError(CompilerLineType lt,cbProject * project,const wxString & filename,long int line,const wxString & error)35 void CompilerErrors::AddError(CompilerLineType lt, cbProject* project, const wxString& filename,
36                               long int line, const wxString& error)
37 {
38     CompileError err;
39     err.lineType = lt;
40     err.project = project;
41     err.filename = filename;
42     err.line = line;
43     err.errors.Add(error);
44     DoAddError(err);
45 }
46 
GotoError(int nr)47 void CompilerErrors::GotoError(int nr)
48 {
49     if (m_Errors.GetCount() == 0 || nr < 0 || nr > (int)m_Errors.GetCount() - 1)
50         return;
51     m_ErrorIndex = nr;
52     DoGotoError(m_Errors[m_ErrorIndex]);
53 }
54 
Next()55 void CompilerErrors::Next()
56 {
57     if (m_ErrorIndex >= (int)m_Errors.GetCount() - 1)
58         return;
59 
60     // locate next *error* (not warning), if there is any
61     bool found = false;
62     int bkp = m_ErrorIndex + 1;
63     while (bkp < (int)m_Errors.GetCount())
64     {
65         if (m_Errors[bkp].lineType == cltError)
66         {
67             const bool isNote = ((m_Errors[bkp].errors.GetCount()>0)
68                                  && m_Errors[bkp].errors[0].StartsWith(_T("note:")));
69             if(!isNote)
70             {
71                 found = true;
72                 m_ErrorIndex = bkp;
73                 break;
74             }
75         }
76         ++bkp;
77     }
78 
79     if (found)
80         DoGotoError(m_Errors[m_ErrorIndex]);
81 }
82 
Previous()83 void CompilerErrors::Previous()
84 {
85     if (m_ErrorIndex <= 0)
86         return;
87 
88     // locate previous *error* (not warning), if there is any
89     bool found = false;
90     int bkp = m_ErrorIndex - 1;
91     while (bkp >= 0)
92     {
93         if (m_Errors[bkp].lineType == cltError)
94         {
95             const bool isNote = ((m_Errors[bkp].errors.GetCount()>0)
96                                  && m_Errors[bkp].errors[0].StartsWith(_T("note:")));
97             if(!isNote)
98             {
99                 found = true;
100                 m_ErrorIndex = bkp;
101                 break;
102             }
103         }
104         --bkp;
105     }
106 
107     if (found)
108         DoGotoError(m_Errors[m_ErrorIndex]);
109 }
110 
Clear()111 void CompilerErrors::Clear()
112 {
113     DoClearErrorMarkFromAllEditors();
114     m_Errors.Clear();
115     m_ErrorIndex = -1;
116 }
117 
DoAddError(const CompileError & error)118 void CompilerErrors::DoAddError(const CompileError& error)
119 {
120 //    int index = ErrorLineHasMore(error.filename, error.line);
121 //    if (index != -1)
122 //    {
123 //        for (unsigned int i = 0; i < error.errors.GetCount(); ++i)
124 //            m_Errors[index].errors.Add(error.errors[i]);
125 //    }
126 //    else
127         m_Errors.Add(error);
128 }
129 
ErrorLineHasMore(const wxString & filename,long int line) const130 int CompilerErrors::ErrorLineHasMore(const wxString& filename, long int line) const
131 {
132     for (unsigned int i = 0; i < m_Errors.GetCount(); ++i)
133     {
134         if (m_Errors[i].filename.Matches(filename) &&
135             m_Errors[i].line == line)
136             return i;
137     }
138     return -1;
139 }
140 
DoGotoError(const CompileError & error)141 void CompilerErrors::DoGotoError(const CompileError& error)
142 {
143     if (error.line <= 0)
144         return;
145     DoClearErrorMarkFromAllEditors();
146     cbEditor* ed = 0;
147     cbProject* project = error.project ? error.project : Manager::Get()->GetProjectManager()->GetActiveProject();
148     if (project && Manager::Get()->GetProjectManager()->IsProjectStillOpen(project))
149     {
150         wxString filename = error.filename;
151         bool isAbsolute = (filename.Length() > 1 && filename.GetChar(1) == ':') ||
152                            filename.StartsWith(_T("/")) ||
153                            filename.StartsWith(_T("\\"));
154         ProjectFile* f = project->GetFileByFilename(error.filename, !isAbsolute, true);
155         if (f)
156         {
157             ed = Manager::Get()->GetEditorManager()->Open(f->file.GetFullPath());
158             if (ed)
159             {
160                 ed->SetProjectFile(f);
161             }
162         }
163         else
164         {
165             if(!isAbsolute) // this is always the case, except for system headers
166                 filename.Prepend(project->GetCommonTopLevelPath());
167 
168             ed = Manager::Get()->GetEditorManager()->Open(filename);
169         }
170     }
171 
172     // if we reached here and ed is NULL, the filename in the output isn't relative
173     // to the project root directory or doesn't belong to the project
174 
175     // first check if we can open it directly...
176     if (!ed)
177         ed = Manager::Get()->GetEditorManager()->Open(error.filename);
178 
179     // check if we find the file among opened files (highly probable for error
180     // messages since we are getting error for something we have just screwed up)
181     if (!ed)
182     {
183         for (int i = 0; i < Manager::Get()->GetEditorManager()->GetEditorsCount(); ++i)
184         {
185             cbEditor* edit = Manager::Get()->GetEditorManager()->GetBuiltinEditor(i);
186             if (!edit)
187                 continue;
188 
189             ProjectFile* pf = edit->GetProjectFile();
190             if (!pf)
191                 continue;
192 
193             if (IsSuffixOfPath(error.filename, pf->file.GetFullPath()))
194             {
195                 ed = Manager::Get()->GetEditorManager()->Open(pf->file.GetFullPath());
196                 break;
197             }
198         }
199     }
200 
201     // finally go through the project files and try to find the file there
202     if (!ed && project)
203     {
204         for (FilesList::iterator it = project->GetFilesList().begin(); it != project->GetFilesList().end(); ++it)
205         {
206             ProjectFile* pf = *it;
207             if (!pf)
208                 continue;
209 
210             if (IsSuffixOfPath(error.filename, pf->file.GetFullPath()))
211             {
212                 ed = Manager::Get()->GetEditorManager()->Open(pf->file.GetFullPath());
213                 break;
214             }
215         }
216     }
217 
218     if (ed)
219     {
220         ed->Activate();
221         ed->UnfoldBlockFromLine(error.line - 1);
222         ed->GotoLine(error.line - 1);
223         ed->SetErrorLine(error.line - 1);
224     }
225 }
226 
DoClearErrorMarkFromAllEditors()227 void CompilerErrors::DoClearErrorMarkFromAllEditors()
228 {
229     EditorManager* edMan = Manager::Get()->GetEditorManager();
230     for (int i = 0; i < edMan->GetEditorsCount(); ++i)
231     {
232         cbEditor* ed = edMan->GetBuiltinEditor(i);
233         if (ed)
234             ed->SetErrorLine(-1);
235     }
236 }
237 
HasNextError() const238 bool CompilerErrors::HasNextError() const
239 {
240     return m_ErrorIndex < (int)m_Errors.GetCount();
241 }
242 
HasPreviousError() const243 bool CompilerErrors::HasPreviousError() const
244 {
245     return m_ErrorIndex > 0;
246 }
247 
GetErrorString(int index)248 wxString CompilerErrors::GetErrorString(int index)
249 {
250     if (m_Errors.GetCount() == 0 || index < 0 || index > (int)m_Errors.GetCount() - 1)
251         return wxEmptyString;
252     wxArrayString& errors = m_Errors[index].errors;
253     wxString error;
254     if (errors.GetCount())
255         error = errors[0];
256     return error;
257 }
258 
GetFirstError() const259 int CompilerErrors::GetFirstError() const
260 {
261     for (unsigned int i = 0; i < m_Errors.GetCount(); ++i)
262     {
263         if (m_Errors[i].lineType == cltError)
264             return i;
265     }
266     return -1;
267 }
268 
GetCount(CompilerLineType lt) const269 unsigned int CompilerErrors::GetCount(CompilerLineType lt) const
270 {
271     unsigned int count = 0;
272     for (unsigned int i = 0; i < m_Errors.GetCount(); ++i)
273     {
274         if (m_Errors[i].lineType == lt)
275             ++count;
276     }
277     return count;
278 }
279