1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "cursor.h"
27
28 #include "clangstring.h"
29 #include "sourcelocation.h"
30 #include "sourcerange.h"
31
32 #include "clangbackend_global.h"
33
34 #include <ostream>
35
36 namespace ClangBackEnd {
37
Cursor()38 Cursor::Cursor()
39 : m_cxCursor(clang_getNullCursor())
40 {
41 }
42
Cursor(CXCursor cxCursor)43 Cursor::Cursor(CXCursor cxCursor)
44 : m_cxCursor(cxCursor)
45 {
46 }
47
isNull() const48 bool Cursor::isNull() const
49 {
50 return clang_Cursor_isNull(m_cxCursor);
51 }
52
isValid() const53 bool Cursor::isValid() const
54 {
55 return !clang_isInvalid(kind());
56 }
57
isTranslationUnit() const58 bool Cursor::isTranslationUnit() const
59 {
60 return clang_isTranslationUnit(kind());
61 }
62
isDefinition() const63 bool Cursor::isDefinition() const
64 {
65 return clang_isCursorDefinition(m_cxCursor);
66 }
67
isDynamicCall() const68 bool Cursor::isDynamicCall() const
69 {
70 return clang_Cursor_isDynamicCall(m_cxCursor);
71 }
72
isVirtualMethod() const73 bool Cursor::isVirtualMethod() const
74 {
75 return clang_CXXMethod_isVirtual(m_cxCursor);
76 }
77
isPureVirtualMethod() const78 bool Cursor::isPureVirtualMethod() const
79 {
80 return clang_CXXMethod_isPureVirtual(m_cxCursor);
81 }
82
isConstantMethod() const83 bool Cursor::isConstantMethod() const
84 {
85 return clang_CXXMethod_isConst(m_cxCursor);
86 }
87
isStaticMethod() const88 bool Cursor::isStaticMethod() const
89 {
90 return clang_CXXMethod_isStatic(m_cxCursor);
91 }
92
isCompoundType() const93 bool Cursor::isCompoundType() const
94 {
95 switch (kind()) {
96 case CXCursor_ClassDecl:
97 case CXCursor_StructDecl:
98 case CXCursor_UnionDecl: return true;
99 default: return false;
100 }
101 }
102
isDeclaration() const103 bool Cursor::isDeclaration() const
104 {
105 return clang_isDeclaration(kind());
106 }
107
isInvalidDeclaration() const108 bool Cursor::isInvalidDeclaration() const
109 {
110 return clang_isInvalidDeclaration(m_cxCursor);
111 }
112
isParameter() const113 bool Cursor::isParameter() const
114 {
115 return kind() == CXCursor_ParmDecl;
116 }
117
isLocalVariable() const118 bool Cursor::isLocalVariable() const
119 {
120 switch (semanticParent().kind()) {
121 case CXCursor_FunctionDecl:
122 case CXCursor_CXXMethod:
123 case CXCursor_Constructor:
124 case CXCursor_Destructor:
125 case CXCursor_ConversionFunction:
126 case CXCursor_FunctionTemplate:
127 case CXCursor_ObjCInstanceMethodDecl: return true;
128 default:
129 return false;
130 }
131 }
132
isReference() const133 bool Cursor::isReference() const
134 {
135 return clang_isReference(kind());
136 }
137
isExpression() const138 bool Cursor::isExpression() const
139 {
140 return clang_isExpression(kind());
141 }
142
isFunctionLike() const143 bool Cursor::isFunctionLike() const
144 {
145 const CXCursorKind k = kind();
146 return k == CXCursor_FunctionDecl
147 || k == CXCursor_CXXMethod
148 || k == CXCursor_FunctionTemplate;
149 }
150
isConstructorOrDestructor() const151 bool Cursor::isConstructorOrDestructor() const
152 {
153 const CXCursorKind k = kind();
154 return k == CXCursor_Constructor
155 || k == CXCursor_Destructor;
156 }
157
isTemplateLike() const158 bool Cursor::isTemplateLike() const
159 {
160 switch (kind()) {
161 case CXCursor_ClassTemplate:
162 case CXCursor_ClassTemplatePartialSpecialization:
163 return true;
164 case CXCursor_ClassDecl:
165 return specializedCursorTemplate().isValid();
166 default:
167 return false;
168 }
169
170 Q_UNREACHABLE();
171 }
172
isAnyTypeAlias() const173 bool Cursor::isAnyTypeAlias() const
174 {
175 const CXCursorKind k = kind();
176 return k == CXCursor_TypeAliasDecl
177 || k == CXCursor_TypedefDecl
178 || k == CXCursor_TypeAliasTemplateDecl;
179 }
180
hasFinalFunctionAttribute() const181 bool Cursor::hasFinalFunctionAttribute() const
182 {
183 bool hasFinal = false;
184
185 visit([&] (Cursor cursor, Cursor /*parent*/) {
186 if (cursor.kind() == CXCursor_CXXFinalAttr) {
187 hasFinal = true;
188 return CXChildVisit_Break;
189 } else {
190 return CXChildVisit_Recurse;
191 }
192 });
193
194 return hasFinal;
195 }
196
hasFinalClassAttribute() const197 bool Cursor::hasFinalClassAttribute() const
198 {
199 bool hasFinal = false;
200
201 visit([&] (Cursor cursor, Cursor /*parent*/) {
202 switch (cursor.kind()) {
203 case CXCursor_CXXFinalAttr:
204 hasFinal = true;
205 return CXChildVisit_Break;
206 case CXCursor_CXXMethod:
207 return CXChildVisit_Break;
208 default:
209 return CXChildVisit_Recurse;
210 }
211 });
212
213 return hasFinal;
214 }
215
isUnexposed() const216 bool Cursor::isUnexposed() const
217 {
218 return clang_isUnexposed(kind());
219 }
220
isAnonymous() const221 bool Cursor::isAnonymous() const
222 {
223 return clang_Cursor_isAnonymous(m_cxCursor);
224 }
225
unifiedSymbolResolution() const226 ClangString Cursor::unifiedSymbolResolution() const
227 {
228 return ClangString(clang_getCursorUSR(m_cxCursor));
229 }
230
mangling() const231 ClangString Cursor::mangling() const
232 {
233 return ClangString(clang_Cursor_getMangling(m_cxCursor));
234 }
235
spelling() const236 ClangString Cursor::spelling() const
237 {
238 return ClangString(clang_getCursorSpelling(m_cxCursor));
239 }
240
displayName() const241 Utf8String Cursor::displayName() const
242 {
243 Utf8String result = ClangString(clang_getCursorDisplayName(m_cxCursor));
244 if (!result.hasContent() && isAnonymous())
245 result = Utf8String("(anonymous)");
246 return result;
247 }
248
briefComment() const249 ClangString Cursor::briefComment() const
250 {
251 return ClangString(clang_Cursor_getBriefCommentText(m_cxCursor));
252 }
253
rawComment() const254 Utf8String Cursor::rawComment() const
255 {
256 Utf8String comment = ClangString(clang_Cursor_getRawCommentText(m_cxCursor));
257 comment.replace(Utf8String("\r\n"), Utf8String("\n"));
258 return comment;
259 }
260
argumentCount() const261 int Cursor::argumentCount() const
262 {
263 return clang_Cursor_getNumArguments(m_cxCursor);
264 }
265
type() const266 Type Cursor::type() const
267 {
268 return clang_getCursorType(m_cxCursor);
269 }
270
nonPointerTupe() const271 Type Cursor::nonPointerTupe() const
272 {
273 auto typeResult = type();
274
275 if (typeResult.isPointer())
276 typeResult = typeResult.pointeeType();
277
278 return typeResult;
279 }
280
enumType() const281 Type Cursor::enumType() const
282 {
283 return clang_getEnumDeclIntegerType(m_cxCursor);
284 }
285
enumConstantValue() const286 long long Cursor::enumConstantValue() const
287 {
288 return clang_getEnumConstantDeclValue(m_cxCursor);
289 }
290
enumConstantUnsignedValue() const291 unsigned long long Cursor::enumConstantUnsignedValue() const
292 {
293 return clang_getEnumConstantDeclUnsignedValue(m_cxCursor);
294 }
295
specializedCursorTemplate() const296 Cursor Cursor::specializedCursorTemplate() const
297 {
298 return clang_getSpecializedCursorTemplate(m_cxCursor);
299 }
300
includedFile() const301 CXFile Cursor::includedFile() const
302 {
303 return clang_getIncludedFile(m_cxCursor);
304 }
305
sourceLocation() const306 SourceLocation Cursor::sourceLocation() const
307 {
308 return {cxTranslationUnit(), clang_getCursorLocation(m_cxCursor)};
309 }
310
cxSourceLocation() const311 CXSourceLocation Cursor::cxSourceLocation() const
312 {
313 return clang_getCursorLocation(m_cxCursor);
314 }
315
sourceRange() const316 SourceRange Cursor::sourceRange() const
317 {
318 return {cxTranslationUnit(), clang_getCursorExtent(m_cxCursor)};
319 }
320
cxSourceRange() const321 CXSourceRange Cursor::cxSourceRange() const
322 {
323 return clang_getCursorExtent(m_cxCursor);
324 }
325
cxTranslationUnit() const326 CXTranslationUnit Cursor::cxTranslationUnit() const
327 {
328 return clang_Cursor_getTranslationUnit(m_cxCursor);
329 }
330
commentRange() const331 SourceRange Cursor::commentRange() const
332 {
333 return {cxTranslationUnit(), clang_Cursor_getCommentRange(m_cxCursor)};
334 }
335
hasSameSourceLocationAs(const Cursor & other) const336 bool Cursor::hasSameSourceLocationAs(const Cursor &other) const
337 {
338 return clang_equalLocations(clang_getCursorLocation(m_cxCursor),
339 clang_getCursorLocation(other.m_cxCursor));
340 }
341
definition() const342 Cursor Cursor::definition() const
343 {
344 return clang_getCursorDefinition(m_cxCursor);
345 }
346
canonical() const347 Cursor Cursor::canonical() const
348 {
349 return clang_getCanonicalCursor(m_cxCursor);
350 }
351
referenced() const352 Cursor Cursor::referenced() const
353 {
354 return clang_getCursorReferenced(m_cxCursor);
355 }
356
semanticParent() const357 Cursor Cursor::semanticParent() const
358 {
359 return clang_getCursorSemanticParent(m_cxCursor);
360 }
361
lexicalParent() const362 Cursor Cursor::lexicalParent() const
363 {
364 return clang_getCursorLexicalParent(m_cxCursor);
365 }
366
functionBaseDeclaration() const367 Cursor Cursor::functionBaseDeclaration() const
368 {
369 auto functionBaseCursor = functionBase();
370
371 if (functionBaseCursor.isValid())
372 return functionBaseCursor.nonPointerTupe().canonical().declaration();
373 else
374 return semanticParent().semanticParent();
375 }
376
functionBase() const377 Cursor Cursor::functionBase() const
378 {
379 Cursor functionBaseCursor;
380
381 visit([&] (Cursor cursor, Cursor /*parentCursor*/) {
382 switch (cursor.kind()) {
383 case CXCursor_DeclRefExpr:
384 functionBaseCursor = cursor; ;
385 return CXChildVisit_Break;
386 default:
387 return CXChildVisit_Recurse;
388 }
389 });
390
391 return functionBaseCursor;
392 }
393
resultType() const394 Type Cursor::resultType() const
395 {
396 return clang_getResultType(type().m_cxType);
397 }
398
argument(int index) const399 Cursor Cursor::argument(int index) const
400 {
401 return clang_Cursor_getArgument(m_cxCursor, index);
402 }
403
overloadedDeclarationsCount() const404 unsigned Cursor::overloadedDeclarationsCount() const
405 {
406 return clang_getNumOverloadedDecls(m_cxCursor);
407 }
408
overloadedDeclaration(unsigned index) const409 Cursor Cursor::overloadedDeclaration(unsigned index) const
410 {
411 return clang_getOverloadedDecl(m_cxCursor, index);
412 }
413
414 namespace {
415
isNotUnexposedLValueReference(const Cursor & argument,const Type & argumentType)416 bool isNotUnexposedLValueReference(const Cursor &argument, const Type &argumentType)
417 {
418 return !(argument.isUnexposed() && argumentType.isLValueReference());
419 }
420
421 }
422
collectOutputArgumentRangesTo(std::vector<CXSourceRange> & outputArgumentRanges) const423 void Cursor::collectOutputArgumentRangesTo(std::vector<CXSourceRange> &outputArgumentRanges) const
424 {
425 const Type callExpressionType = referenced().type();
426 const int argumentCount = this->argumentCount();
427 const std::size_t maxSize = std::size_t(std::max(0, argumentCount))
428 + outputArgumentRanges.size();
429 outputArgumentRanges.reserve(maxSize);
430
431 for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
432 const Cursor argument = this->argument(argumentIndex);
433 const Type argumentType = callExpressionType.argument(argumentIndex);
434
435 if (isNotUnexposedLValueReference(argument, argumentType)
436 && argumentType.isOutputArgument()) {
437 outputArgumentRanges.push_back(argument.cxSourceRange());
438 }
439 }
440 }
441
outputArgumentRanges() const442 std::vector<CXSourceRange> Cursor::outputArgumentRanges() const
443 {
444 std::vector<CXSourceRange> outputArgumentRanges;
445
446 collectOutputArgumentRangesTo(outputArgumentRanges);
447
448 return outputArgumentRanges;
449 }
450
kind() const451 CXCursorKind Cursor::kind() const
452 {
453 return clang_getCursorKind(m_cxCursor);
454 }
455
cx() const456 CXCursor Cursor::cx() const
457 {
458 return m_cxCursor;
459 }
460
storageClass() const461 StorageClass Cursor::storageClass() const
462 {
463 CXCursor cursor = m_cxCursor;
464 if (!isDeclaration())
465 cursor = referenced().m_cxCursor;
466 const CX_StorageClass cxStorageClass = clang_Cursor_getStorageClass(cursor);
467 switch (cxStorageClass) {
468 case CX_SC_Invalid:
469 case CX_SC_OpenCLWorkGroupLocal:
470 break;
471 case CX_SC_None:
472 return StorageClass::None;
473 case CX_SC_Extern:
474 return StorageClass::Extern;
475 case CX_SC_Static:
476 return StorageClass::Static;
477 case CX_SC_PrivateExtern:
478 return StorageClass::PrivateExtern;
479 case CX_SC_Auto:
480 return StorageClass::Auto;
481 case CX_SC_Register:
482 return StorageClass::Register;
483 }
484 return StorageClass::Invalid;
485 }
486
accessSpecifier() const487 AccessSpecifier Cursor::accessSpecifier() const
488 {
489 CXCursor cursor = m_cxCursor;
490 if (!isDeclaration())
491 cursor = referenced().m_cxCursor;
492 const CX_CXXAccessSpecifier cxAccessSpecifier = clang_getCXXAccessSpecifier(cursor);
493 switch (cxAccessSpecifier) {
494 case CX_CXXInvalidAccessSpecifier:
495 break;
496 case CX_CXXPublic:
497 return AccessSpecifier::Public;
498 case CX_CXXProtected:
499 return AccessSpecifier::Protected;
500 case CX_CXXPrivate:
501 return AccessSpecifier::Private;
502 }
503 return AccessSpecifier::Invalid;
504 }
505
operator ==(const Cursor & first,const Cursor & second)506 bool operator==(const Cursor &first, const Cursor &second)
507 {
508 return clang_equalCursors(first.m_cxCursor, second.m_cxCursor);
509 }
510
operator !=(const Cursor & first,const Cursor & second)511 bool operator!=(const Cursor &first, const Cursor &second)
512 {
513 return !(first == second);
514 }
515
operator <<(std::ostream & os,CXCursorKind cursorKind)516 std::ostream &operator<<(std::ostream &os, CXCursorKind cursorKind)
517 {
518 ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));
519 return os << cursorKindSpelling.cString();
520 }
521
operator <<(std::ostream & os,const Cursor & cursor)522 std::ostream &operator<<(std::ostream &os, const Cursor &cursor)
523 {
524 if (cursor.isValid()) {
525 ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursor.kind()));
526 os << cursorKindSpelling << " ";
527
528 auto identifier = cursor.displayName();
529 if (identifier.hasContent()) {
530 os << "\""
531 << identifier
532 << "\": ";
533 }
534
535 os << cursor.sourceLocation();
536 } else {
537 os << "Invalid cursor!";
538 }
539
540 return os;
541 }
542
543 } // namespace ClangBackEnd
544
545