1 | /* |
2 | * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) |
3 | * |
4 | * This program is free software: you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation, either version 3 of the License, or |
7 | * (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
16 | */ |
17 | #include "parserutils.h" |
18 | |
19 | #include <QDir> |
20 | #include <QFile> |
21 | #include <QFileInfo> |
22 | #include <QDebug> |
23 | #include <QGlobalStatic> |
24 | #include "../utils.h" |
25 | |
26 | QStringList CppDirectives; |
27 | QStringList JavadocTags; |
28 | QMap<QString,SkipType> CppKeywords; |
29 | QSet<QString> CppControlKeyWords; |
30 | QSet<QString> CppTypeKeywords; |
31 | QSet<QString> CKeywords; |
32 | QSet<QString> STLPointers; |
33 | QSet<QString> STLContainers; |
34 | QSet<QString> STLElementMethods; |
35 | QSet<QString> MemberOperators; |
36 | QSet<QString> IOManipulators; |
37 | |
38 | Q_GLOBAL_STATIC(QSet<QString>,) |
39 | Q_GLOBAL_STATIC(QSet<QString>,CppSourceExts) |
40 | |
41 | void initParser() |
42 | { |
43 | CppHeaderExts->insert("h" ); |
44 | CppHeaderExts->insert("hpp" ); |
45 | CppHeaderExts->insert("rh" ); |
46 | CppHeaderExts->insert("hh" ); |
47 | CppHeaderExts->insert("hxx" ); |
48 | CppHeaderExts->insert("inl" ); |
49 | CppHeaderExts->insert("" ); |
50 | |
51 | CppSourceExts->insert("c" ); |
52 | CppSourceExts->insert("cpp" ); |
53 | CppSourceExts->insert("cc" ); |
54 | CppSourceExts->insert("cxx" ); |
55 | CppSourceExts->insert("c++" ); |
56 | CppSourceExts->insert("cp" ); |
57 | // skip itself |
58 | CppKeywords.insert("and" ,SkipType::skItself); |
59 | CppKeywords.insert("and_eq" ,SkipType::skItself); |
60 | CppKeywords.insert("bitand" ,SkipType::skItself); |
61 | CppKeywords.insert("bitor" ,SkipType::skItself); |
62 | CppKeywords.insert("break" ,SkipType::skItself); |
63 | CppKeywords.insert("compl" ,SkipType::skItself); |
64 | CppKeywords.insert("constexpr" ,SkipType::skItself); |
65 | CppKeywords.insert("const_cast" ,SkipType::skItself); |
66 | CppKeywords.insert("continue" ,SkipType::skItself); |
67 | CppKeywords.insert("dynamic_cast" ,SkipType::skItself); |
68 | CppKeywords.insert("else" ,SkipType::skItself); |
69 | CppKeywords.insert("explicit" ,SkipType::skItself); |
70 | CppKeywords.insert("export" ,SkipType::skItself); |
71 | CppKeywords.insert("false" ,SkipType::skItself); |
72 | //CppKeywords.insert("for",SkipType::skItself); |
73 | CppKeywords.insert("mutable" ,SkipType::skItself); |
74 | CppKeywords.insert("noexcept" ,SkipType::skItself); |
75 | CppKeywords.insert("not" ,SkipType::skItself); |
76 | CppKeywords.insert("not_eq" ,SkipType::skItself); |
77 | CppKeywords.insert("nullptr" ,SkipType::skItself); |
78 | CppKeywords.insert("or" ,SkipType::skItself); |
79 | CppKeywords.insert("or_eq" ,SkipType::skItself); |
80 | CppKeywords.insert("register" ,SkipType::skItself); |
81 | CppKeywords.insert("reinterpret_cast" ,SkipType::skItself); |
82 | CppKeywords.insert("static_assert" ,SkipType::skItself); |
83 | CppKeywords.insert("static_cast" ,SkipType::skItself); |
84 | CppKeywords.insert("template" ,SkipType::skItself); |
85 | //CppKeywords.insert("this",SkipType::skItself); |
86 | CppKeywords.insert("thread_local" ,SkipType::skItself); |
87 | CppKeywords.insert("true" ,SkipType::skItself); |
88 | CppKeywords.insert("typename" ,SkipType::skItself); |
89 | CppKeywords.insert("virtual" ,SkipType::skItself); |
90 | CppKeywords.insert("volatile" ,SkipType::skItself); |
91 | CppKeywords.insert("xor" ,SkipType::skItself); |
92 | CppKeywords.insert("xor_eq" ,SkipType::skItself); |
93 | |
94 | |
95 | //CppKeywords.insert("catch",SkipType::skItself); |
96 | CppKeywords.insert("do" ,SkipType::skItself); |
97 | CppKeywords.insert("try" ,SkipType::skItself); |
98 | |
99 | // Skip to ; |
100 | CppKeywords.insert("delete" ,SkipType::skToSemicolon); |
101 | CppKeywords.insert("delete[]" ,SkipType::skToSemicolon); |
102 | CppKeywords.insert("goto" ,SkipType::skToSemicolon); |
103 | CppKeywords.insert("new" ,SkipType::skToSemicolon); |
104 | CppKeywords.insert("return" ,SkipType::skToSemicolon); |
105 | CppKeywords.insert("throw" ,SkipType::skToSemicolon); |
106 | // CppKeywords.insert("using",SkipType::skToSemicolon); //won't use it |
107 | |
108 | // Skip to : |
109 | CppKeywords.insert("case" ,SkipType::skToColon); |
110 | CppKeywords.insert("default" ,SkipType::skToColon); |
111 | |
112 | // Skip to ) |
113 | CppKeywords.insert("__attribute__" ,SkipType::skToRightParenthesis); |
114 | CppKeywords.insert("alignas" ,SkipType::skToRightParenthesis); // not right |
115 | CppKeywords.insert("alignof" ,SkipType::skToRightParenthesis); // not right |
116 | CppKeywords.insert("decltype" ,SkipType::skToRightParenthesis); // not right |
117 | CppKeywords.insert("if" ,SkipType::skToRightParenthesis); |
118 | CppKeywords.insert("sizeof" ,SkipType::skToRightParenthesis); |
119 | CppKeywords.insert("switch" ,SkipType::skToRightParenthesis); |
120 | CppKeywords.insert("typeid" ,SkipType::skToRightParenthesis); |
121 | CppKeywords.insert("while" ,SkipType::skToRightParenthesis); |
122 | |
123 | // Skip to } |
124 | CppKeywords.insert("asm" ,SkipType::skToRightBrace); |
125 | //CppKeywords.insert("namespace",SkipType::skToLeftBrace); // won't process it |
126 | // Skip to { |
127 | |
128 | // wont handle |
129 | |
130 | //Not supported yet |
131 | CppKeywords.insert("atomic_cancel" ,SkipType::skNone); |
132 | CppKeywords.insert("atomic_commit" ,SkipType::skNone); |
133 | CppKeywords.insert("atomic_noexcept" ,SkipType::skNone); |
134 | CppKeywords.insert("concept" ,SkipType::skNone); |
135 | CppKeywords.insert("consteval" ,SkipType::skNone); |
136 | CppKeywords.insert("constinit" ,SkipType::skNone); |
137 | CppKeywords.insert("co_wait" ,SkipType::skNone); |
138 | CppKeywords.insert("co_return" ,SkipType::skNone); |
139 | CppKeywords.insert("co_yield" ,SkipType::skNone); |
140 | CppKeywords.insert("reflexpr" ,SkipType::skNone); |
141 | CppKeywords.insert("requires" ,SkipType::skNone); |
142 | |
143 | // its a type |
144 | CppKeywords.insert("auto" ,SkipType::skNone); |
145 | CppKeywords.insert("bool" ,SkipType::skNone); |
146 | CppKeywords.insert("char" ,SkipType::skNone); |
147 | CppKeywords.insert("char8_t" ,SkipType::skNone); |
148 | CppKeywords.insert("char16_t" ,SkipType::skNone); |
149 | CppKeywords.insert("char32_t" ,SkipType::skNone); |
150 | CppKeywords.insert("double" ,SkipType::skNone); |
151 | CppKeywords.insert("float" ,SkipType::skNone); |
152 | CppKeywords.insert("int" ,SkipType::skNone); |
153 | CppKeywords.insert("long" ,SkipType::skNone); |
154 | CppKeywords.insert("short" ,SkipType::skNone); |
155 | CppKeywords.insert("signed" ,SkipType::skNone); |
156 | CppKeywords.insert("unsigned" ,SkipType::skNone); |
157 | CppKeywords.insert("void" ,SkipType::skNone); |
158 | CppKeywords.insert("wchar_t" ,SkipType::skNone); |
159 | |
160 | // type keywords |
161 | CppTypeKeywords.insert("auto" ); |
162 | CppTypeKeywords.insert("bool" ); |
163 | CppTypeKeywords.insert("char" ); |
164 | CppTypeKeywords.insert("char8_t" ); |
165 | CppTypeKeywords.insert("char16_t" ); |
166 | CppTypeKeywords.insert("char32_t" ); |
167 | CppTypeKeywords.insert("double" ); |
168 | CppTypeKeywords.insert("float" ); |
169 | CppTypeKeywords.insert("int" ); |
170 | CppTypeKeywords.insert("long" ); |
171 | CppTypeKeywords.insert("short" ); |
172 | //CppTypeKeywords.insert("signed"); |
173 | //CppTypeKeywords.insert("unsigned"); |
174 | CppTypeKeywords.insert("void" ); |
175 | CppTypeKeywords.insert("wchar_t" ); |
176 | CppTypeKeywords.insert("signed" ); |
177 | CppTypeKeywords.insert("unsigned" ); |
178 | |
179 | // it's part of type info |
180 | CppKeywords.insert("const" ,SkipType::skNone); |
181 | CppKeywords.insert("extern" ,SkipType::skNone); |
182 | CppKeywords.insert("inline" ,SkipType::skNone); |
183 | |
184 | // handled elsewhere |
185 | CppKeywords.insert("class" ,SkipType::skNone); |
186 | CppKeywords.insert("enum" ,SkipType::skNone); |
187 | CppKeywords.insert("friend" ,SkipType::skNone); |
188 | CppKeywords.insert("operator" ,SkipType::skNone); |
189 | CppKeywords.insert("private" ,SkipType::skNone); |
190 | CppKeywords.insert("protected" ,SkipType::skNone); |
191 | CppKeywords.insert("public" ,SkipType::skNone); |
192 | CppKeywords.insert("static" ,SkipType::skNone); |
193 | CppKeywords.insert("struct" ,SkipType::skNone); |
194 | CppKeywords.insert("typedef" ,SkipType::skNone); |
195 | CppKeywords.insert("union" ,SkipType::skNone); |
196 | // namespace |
197 | CppKeywords.insert("namespace" ,SkipType::skNone); |
198 | CppKeywords.insert("using" ,SkipType::skNone); |
199 | |
200 | CppKeywords.insert("for" ,SkipType::skNone); |
201 | CppKeywords.insert("catch" ,SkipType::skNone); |
202 | |
203 | |
204 | |
205 | // nullptr is value |
206 | CppKeywords.insert("nullptr" ,SkipType::skNone); |
207 | |
208 | //C Keywords |
209 | CKeywords.insert("auto" ); |
210 | CKeywords.insert("break" ); |
211 | CKeywords.insert("case" ); |
212 | CKeywords.insert("char" ); |
213 | CKeywords.insert("const" ); |
214 | CKeywords.insert("continue" ); |
215 | CKeywords.insert("default" ); |
216 | CKeywords.insert("do" ); |
217 | CKeywords.insert("double" ); |
218 | CKeywords.insert("else" ); |
219 | CKeywords.insert("enum" ); |
220 | CKeywords.insert("extern" ); |
221 | CKeywords.insert("float" ); |
222 | CKeywords.insert("for" ); |
223 | CKeywords.insert("goto" ); |
224 | CKeywords.insert("if" ); |
225 | CKeywords.insert("inline" ); |
226 | CKeywords.insert("int" ); |
227 | CKeywords.insert("long" ); |
228 | CKeywords.insert("register" ); |
229 | CKeywords.insert("restrict" ); |
230 | CKeywords.insert("return" ); |
231 | CKeywords.insert("short" ); |
232 | CKeywords.insert("signed" ); |
233 | CKeywords.insert("sizeof" ); |
234 | CKeywords.insert("static" ); |
235 | CKeywords.insert("struct" ); |
236 | CKeywords.insert("switch" ); |
237 | CKeywords.insert("typedef" ); |
238 | CKeywords.insert("union" ); |
239 | CKeywords.insert("unsigned" ); |
240 | CKeywords.insert("void" ); |
241 | CKeywords.insert("volatile" ); |
242 | CKeywords.insert("while" ); |
243 | |
244 | CppControlKeyWords.insert("for" ); |
245 | CppControlKeyWords.insert("if" ); |
246 | CppControlKeyWords.insert("catch" ); |
247 | |
248 | //STL Containers |
249 | STLContainers.insert("std::array" ); |
250 | STLContainers.insert("std::vector" ); |
251 | STLContainers.insert("std::deque" ); |
252 | STLContainers.insert("std::forward_list" ); |
253 | STLContainers.insert("std::list" ); |
254 | |
255 | STLContainers.insert("std::set" ); |
256 | STLContainers.insert("std::map" ); |
257 | STLContainers.insert("std::multilist" ); |
258 | STLContainers.insert("std::multimap" ); |
259 | |
260 | STLContainers.insert("std::unordered_set" ); |
261 | STLContainers.insert("std::unordered_map" ); |
262 | STLContainers.insert("std::unordered_multiset" ); |
263 | STLContainers.insert("std::unordered_multimap" ); |
264 | |
265 | STLContainers.insert("std::stack" ); |
266 | STLContainers.insert("std::queue" ); |
267 | STLContainers.insert("std::priority_queue" ); |
268 | |
269 | STLContainers.insert("std::span" ); |
270 | |
271 | //STL element access methods |
272 | STLElementMethods.insert("at" ); |
273 | STLElementMethods.insert("back" ); |
274 | STLElementMethods.insert("front" ); |
275 | STLElementMethods.insert("top" ); |
276 | |
277 | //STL pointers |
278 | STLPointers.insert("std::unique_ptr" ); |
279 | STLPointers.insert("std::auto_ptr" ); |
280 | STLPointers.insert("std::shared_ptr" ); |
281 | STLPointers.insert("std::weak_ptr" ); |
282 | STLPointers.insert("__gnu_cxx::__normal_iterator" ); |
283 | STLPointers.insert("std::reverse_iterator" ); |
284 | STLPointers.insert("std::iterator" ); |
285 | |
286 | //C/CPP preprocessor directives |
287 | CppDirectives.append("#include" ); |
288 | CppDirectives.append("#if" ); |
289 | CppDirectives.append("#ifdef" ); |
290 | CppDirectives.append("#ifndef" ); |
291 | CppDirectives.append("#else" ); |
292 | CppDirectives.append("#elif" ); |
293 | CppDirectives.append("#endif" ); |
294 | CppDirectives.append("#define" ); |
295 | CppDirectives.append("#error" ); |
296 | CppDirectives.append("#pragma" ); |
297 | CppDirectives.append("#line" ); |
298 | CppDirectives.append("#undef" ); |
299 | |
300 | // javadoc tags |
301 | JavadocTags.append("@author" ); |
302 | JavadocTags.append("@code" ); |
303 | JavadocTags.append("@docRoot" ); |
304 | JavadocTags.append("@deprecated" ); |
305 | JavadocTags.append("@exception" ); |
306 | JavadocTags.append("@inheritDoc" ); |
307 | JavadocTags.append("@link" ); |
308 | JavadocTags.append("@linkplain" ); |
309 | JavadocTags.append("@literal" ); |
310 | JavadocTags.append("@param" ); |
311 | JavadocTags.append("@return" ); |
312 | JavadocTags.append("@see" ); |
313 | JavadocTags.append("@serial" ); |
314 | JavadocTags.append("@serialData" ); |
315 | JavadocTags.append("@serialField" ); |
316 | JavadocTags.append("@since" ); |
317 | JavadocTags.append("@throws" ); |
318 | JavadocTags.append("@value" ); |
319 | JavadocTags.append("@version" ); |
320 | |
321 | MemberOperators.insert("." ); |
322 | MemberOperators.insert("::" ); |
323 | MemberOperators.insert("->" ); |
324 | MemberOperators.insert("->*" ); |
325 | MemberOperators.insert(".*" ); |
326 | |
327 | IOManipulators.insert("std::boolalpha" ); |
328 | IOManipulators.insert("std::noboolalpha" ); |
329 | IOManipulators.insert("std::showbase" ); |
330 | IOManipulators.insert("std::noshowbase" ); |
331 | IOManipulators.insert("std::showpoint" ); |
332 | IOManipulators.insert("std::noshowpoint" ); |
333 | IOManipulators.insert("std::showpos" ); |
334 | IOManipulators.insert("std::noshowpos" ); |
335 | IOManipulators.insert("std::skipws" ); |
336 | IOManipulators.insert("std::noskipws" ); |
337 | |
338 | IOManipulators.insert("std::uppercase" ); |
339 | IOManipulators.insert("std::nouppercase" ); |
340 | IOManipulators.insert("std::unitbuf" ); |
341 | IOManipulators.insert("std::nounitbuf" ); |
342 | IOManipulators.insert("std::left" ); |
343 | IOManipulators.insert("std::right" ); |
344 | IOManipulators.insert("std::internal" ); |
345 | IOManipulators.insert("std::dec" ); |
346 | IOManipulators.insert("std::hex" ); |
347 | IOManipulators.insert("std::oct" ); |
348 | |
349 | IOManipulators.insert("std::fixed" ); |
350 | IOManipulators.insert("std::scientific" ); |
351 | IOManipulators.insert("std::hexfloat" ); |
352 | IOManipulators.insert("std::defaultfloat" ); |
353 | IOManipulators.insert("std::ws" ); |
354 | IOManipulators.insert("std::ends" ); |
355 | IOManipulators.insert("std::flush" ); |
356 | IOManipulators.insert("std::endl" ); |
357 | |
358 | } |
359 | |
360 | QString (const QString &relativeTo, const QString &line, |
361 | const QStringList& includePaths, const QStringList& projectIncludePaths) { |
362 | QString result = "" ; |
363 | |
364 | // Handle <> |
365 | int openTokenPos = line.indexOf('<'); |
366 | if (openTokenPos >= 0) { |
367 | int closeTokenPos = line.indexOf('>',openTokenPos+1); |
368 | if (closeTokenPos >=0) { |
369 | QString fileName = line.mid(openTokenPos + 1, closeTokenPos - openTokenPos - 1); |
370 | //project settings is preferred |
371 | result = getSystemHeaderFilename(fileName, projectIncludePaths); |
372 | if (result.isEmpty()) { |
373 | result = getSystemHeaderFilename(fileName, includePaths); |
374 | } |
375 | } |
376 | } else { |
377 | // Try "" |
378 | openTokenPos = line.indexOf('"'); |
379 | if (openTokenPos >= 0) { |
380 | int closeTokenPos = line.indexOf('"', openTokenPos+1); |
381 | if (closeTokenPos >= 0) { |
382 | QString fileName = line.mid(openTokenPos + 1, closeTokenPos - openTokenPos - 1); |
383 | result = getLocalHeaderFilename(relativeTo, fileName); |
384 | //project settings is preferred |
385 | if (result.isEmpty()) { |
386 | result = getSystemHeaderFilename(fileName, projectIncludePaths); |
387 | } |
388 | if (result.isEmpty()) { |
389 | result = getSystemHeaderFilename(fileName, includePaths); |
390 | } |
391 | } |
392 | } |
393 | } |
394 | return result; |
395 | } |
396 | |
397 | QString (const QString &relativeTo, const QString &fileName) |
398 | { |
399 | QFileInfo relativeFile(relativeTo); |
400 | QDir dir = relativeFile.dir(); |
401 | // Search local directory |
402 | if (dir.exists(fileName)) { |
403 | return dir.absoluteFilePath(fileName); |
404 | } |
405 | return "" ; |
406 | } |
407 | |
408 | QString (const QString &fileName, const QStringList& includePaths) |
409 | { |
410 | |
411 | // Search compiler include directories |
412 | for (const QString& path:includePaths) { |
413 | QDir dir(path); |
414 | if (dir.exists(fileName)) |
415 | return dir.absoluteFilePath(fileName); |
416 | } |
417 | //not found |
418 | return "" ; |
419 | } |
420 | |
421 | bool (const QString &fileName, const QSet<QString> &includePaths) |
422 | { |
423 | if (fileName.isEmpty()) |
424 | return false; |
425 | if (includePaths.isEmpty()) |
426 | return false; |
427 | bool isFullName = false; |
428 | |
429 | #ifdef Q_OS_WIN |
430 | isFullName = fileName.startsWith("/" ) || (fileName.length()>2 && fileName[1]==':'); |
431 | #else |
432 | isFullName = fileName.startsWith("/" ); |
433 | #endif |
434 | if (isFullName) { |
435 | QFileInfo info(fileName); |
436 | // If it's a full file name, check if its directory is an include path |
437 | if (info.exists()) { // full file name |
438 | QDir dir = info.dir(); |
439 | QString absPath = includeTrailingPathDelimiter(dir.absolutePath()); |
440 | foreach (const QString& incPath, includePaths) { |
441 | if (absPath.startsWith(incPath)) |
442 | return true; |
443 | } |
444 | } |
445 | } else { |
446 | //check if it's in the include dir |
447 | for (const QString& includePath: includePaths) { |
448 | QDir dir(includePath); |
449 | if (dir.exists(fileName)) |
450 | return true; |
451 | } |
452 | } |
453 | return false; |
454 | } |
455 | |
456 | bool isCppKeyword(const QString &word) |
457 | { |
458 | return CppKeywords.contains(word); |
459 | } |
460 | |
461 | bool isHFile(const QString& filename) |
462 | { |
463 | if (filename.isEmpty()) |
464 | return false; |
465 | |
466 | QFileInfo fileInfo(filename); |
467 | return CppHeaderExts->contains(fileInfo.suffix().toLower()); |
468 | |
469 | } |
470 | |
471 | bool isCFile(const QString& filename) |
472 | { |
473 | if (filename.isEmpty()) |
474 | return false; |
475 | |
476 | QFileInfo fileInfo(filename); |
477 | return CppSourceExts->contains(fileInfo.suffix().toLower()); |
478 | } |
479 | |
480 | PStatement CppScopes::findScopeAtLine(int line) |
481 | { |
482 | if (mScopes.isEmpty()) |
483 | return PStatement(); |
484 | int start = 0; |
485 | int end = mScopes.size()-1; |
486 | while (start<=end) { |
487 | int mid = (start+end)/2; |
488 | PCppScope midScope = mScopes[mid]; |
489 | if (midScope->startLine == line) { |
490 | while (mid-1>=0 && (mScopes[mid-1]->startLine == line)) { |
491 | mid--; |
492 | } |
493 | return mScopes[mid]->statement; |
494 | } else if (midScope->startLine > line) { |
495 | end = mid-1; |
496 | } else { |
497 | start = mid+1; |
498 | } |
499 | } |
500 | if (end>=0) |
501 | return mScopes[end]->statement; |
502 | else |
503 | return PStatement(); |
504 | } |
505 | |
506 | void CppScopes::addScope(int line, PStatement scopeStatement) |
507 | { |
508 | PCppScope scope = std::make_shared<CppScope>(); |
509 | scope->startLine = line; |
510 | scope->statement = scopeStatement; |
511 | mScopes.append(scope); |
512 | if (!mScopes.isEmpty() && mScopes.back()->startLine>line) { |
513 | qDebug()<<QString("Error: new scope %1 at %2 which is less that last scope %3" ) |
514 | .arg(scopeStatement->fullName, line,mScopes.back()->startLine>line); |
515 | } |
516 | } |
517 | |
518 | PStatement CppScopes::lastScope() |
519 | { |
520 | if (mScopes.isEmpty()) |
521 | return PStatement(); |
522 | return mScopes.back()->statement; |
523 | } |
524 | |
525 | void CppScopes::removeLastScope() |
526 | { |
527 | if (!mScopes.isEmpty()) |
528 | mScopes.pop_back(); |
529 | } |
530 | |
531 | void CppScopes::clear() |
532 | { |
533 | mScopes.clear(); |
534 | } |
535 | |
536 | MemberOperatorType getOperatorType(const QString &phrase, int index) |
537 | { |
538 | if (index>=phrase.length()) |
539 | return MemberOperatorType::otOther; |
540 | if (phrase[index] == '.') |
541 | return MemberOperatorType::otDot; |
542 | if (index+1>=phrase.length()) |
543 | return MemberOperatorType::otOther; |
544 | if ((phrase[index] == '-') && (phrase[index+1] == '>')) |
545 | return MemberOperatorType::otArrow; |
546 | if ((phrase[index] == ':') && (phrase[index+1] == ':')) |
547 | return MemberOperatorType::otDColon; |
548 | return MemberOperatorType::otOther; |
549 | } |
550 | |
551 | bool isScopeTypeKind(StatementKind kind) |
552 | { |
553 | switch(kind) { |
554 | case StatementKind::skClass: |
555 | case StatementKind::skNamespace: |
556 | case StatementKind::skEnumType: |
557 | case StatementKind::skEnumClassType: |
558 | return true; |
559 | default: |
560 | return false; |
561 | } |
562 | } |
563 | |
564 | EvalStatement::EvalStatement( |
565 | const QString &baseType, |
566 | EvalStatementKind kind, |
567 | const PStatement &baseStatement, |
568 | const PStatement &typeStatement, |
569 | int pointerLevel) |
570 | { |
571 | this->baseType = baseType; |
572 | this->kind = kind; |
573 | this->baseStatement = baseStatement; |
574 | this->effectiveTypeStatement = typeStatement; |
575 | this->pointerLevel = pointerLevel; |
576 | } |
577 | |
578 | void EvalStatement::assignType(const PEvalStatement &typeStatement) |
579 | { |
580 | Q_ASSERT(typeStatement && typeStatement->kind==EvalStatementKind::Type); |
581 | baseType = typeStatement->baseType; |
582 | pointerLevel = typeStatement->pointerLevel; |
583 | effectiveTypeStatement = typeStatement->effectiveTypeStatement; |
584 | } |
585 | |
586 | QStringList getOwnerExpressionAndMember(const QStringList expression, QString &memberOperator, QStringList &memberExpression) |
587 | { |
588 | //find position of the last member operator |
589 | int lastMemberOperatorPos = -1; |
590 | int currentMatchingLevel = 0; |
591 | QString matchingSignLeft; |
592 | QString matchingSignRight; |
593 | for (int i=0;i<expression.length();i++) { |
594 | QString token = expression[i]; |
595 | if (currentMatchingLevel == 0) { |
596 | if (isMemberOperator(token)) { |
597 | lastMemberOperatorPos = i; |
598 | } else if (token == "(" ) { |
599 | matchingSignLeft = "(" ; |
600 | matchingSignRight = ")" ; |
601 | currentMatchingLevel++; |
602 | } else if (token == "[" ) { |
603 | matchingSignLeft = "[" ; |
604 | matchingSignRight = "]" ; |
605 | currentMatchingLevel++; |
606 | } else if (token == "<" ) { |
607 | matchingSignLeft = "<" ; |
608 | matchingSignRight = ">" ; |
609 | currentMatchingLevel++; |
610 | } |
611 | } else { |
612 | if (token == matchingSignLeft) { |
613 | currentMatchingLevel++; |
614 | } else if (token == matchingSignRight) { |
615 | currentMatchingLevel--; |
616 | } |
617 | } |
618 | } |
619 | |
620 | QStringList ownerExpression; |
621 | if (lastMemberOperatorPos<0) { |
622 | memberOperator = "" ; |
623 | memberExpression = expression; |
624 | } else { |
625 | memberOperator = expression[lastMemberOperatorPos]; |
626 | memberExpression = expression.mid(lastMemberOperatorPos+1); |
627 | ownerExpression = expression.mid(0,lastMemberOperatorPos); |
628 | } |
629 | if (memberExpression.length()>1) { |
630 | memberExpression = memberExpression.mid(memberExpression.length()-1,1); |
631 | } |
632 | return ownerExpression; |
633 | |
634 | } |
635 | |
636 | bool isMemberOperator(QString token) |
637 | { |
638 | return MemberOperators.contains(token); |
639 | } |
640 | |
641 | |
642 | StatementKind getKindOfStatement(const PStatement& statement) |
643 | { |
644 | if (!statement) |
645 | return StatementKind::skUnknown; |
646 | if (statement->kind == StatementKind::skVariable) { |
647 | if (!statement->parentScope.lock()) { |
648 | return StatementKind::skGlobalVariable; |
649 | } else if (statement->scope == StatementScope::ssLocal) { |
650 | return StatementKind::skLocalVariable; |
651 | } else { |
652 | return StatementKind::skVariable; |
653 | } |
654 | } |
655 | return statement->kind; |
656 | } |
657 | |
658 | bool isCppFile(const QString &filename) |
659 | { |
660 | if (isCFile(filename) && !filename.endsWith(".c" )) |
661 | return true; |
662 | return false; |
663 | } |
664 | |
665 | bool isCppControlKeyword(const QString &word) |
666 | { |
667 | return CppControlKeyWords.contains(word); |
668 | } |
669 | |