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