1 //===- CIndexCXX.cpp - Clang-C Source Indexing Library --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the libclang support for C++ cursors.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CIndexer.h"
14 #include "CXCursor.h"
15 #include "CXType.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/DeclTemplate.h"
18 
19 using namespace clang;
20 using namespace clang::cxcursor;
21 
clang_isVirtualBase(CXCursor C)22 unsigned clang_isVirtualBase(CXCursor C) {
23   if (C.kind != CXCursor_CXXBaseSpecifier)
24     return 0;
25 
26   const CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
27   return B->isVirtual();
28 }
29 
clang_getCXXAccessSpecifier(CXCursor C)30 enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) {
31   AccessSpecifier spec = AS_none;
32 
33   if (C.kind == CXCursor_CXXAccessSpecifier || clang_isDeclaration(C.kind))
34     spec = getCursorDecl(C)->getAccess();
35   else if (C.kind == CXCursor_CXXBaseSpecifier)
36     spec = getCursorCXXBaseSpecifier(C)->getAccessSpecifier();
37   else
38     return CX_CXXInvalidAccessSpecifier;
39 
40   switch (spec) {
41     case AS_public: return CX_CXXPublic;
42     case AS_protected: return CX_CXXProtected;
43     case AS_private: return CX_CXXPrivate;
44     case AS_none: return CX_CXXInvalidAccessSpecifier;
45   }
46 
47   llvm_unreachable("Invalid AccessSpecifier!");
48 }
49 
clang_getTemplateCursorKind(CXCursor C)50 enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
51   using namespace clang::cxcursor;
52 
53   switch (C.kind) {
54   case CXCursor_ClassTemplate:
55   case CXCursor_FunctionTemplate:
56     if (const TemplateDecl *Template
57                            = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C)))
58       return MakeCXCursor(Template->getTemplatedDecl(), getCursorTU(C)).kind;
59     break;
60 
61   case CXCursor_ClassTemplatePartialSpecialization:
62     if (const ClassTemplateSpecializationDecl *PartialSpec
63           = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(
64                                                             getCursorDecl(C))) {
65       switch (PartialSpec->getTagKind()) {
66       case TTK_Interface:
67       case TTK_Struct: return CXCursor_StructDecl;
68       case TTK_Class: return CXCursor_ClassDecl;
69       case TTK_Union: return CXCursor_UnionDecl;
70       case TTK_Enum: return CXCursor_NoDeclFound;
71       }
72     }
73     break;
74 
75   default:
76     break;
77   }
78 
79   return CXCursor_NoDeclFound;
80 }
81 
clang_getSpecializedCursorTemplate(CXCursor C)82 CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {
83   if (!clang_isDeclaration(C.kind))
84     return clang_getNullCursor();
85 
86   const Decl *D = getCursorDecl(C);
87   if (!D)
88     return clang_getNullCursor();
89 
90   Decl *Template = nullptr;
91   if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
92     if (const ClassTemplatePartialSpecializationDecl *PartialSpec
93           = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
94       Template = PartialSpec->getSpecializedTemplate();
95     else if (const ClassTemplateSpecializationDecl *ClassSpec
96                = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
97       llvm::PointerUnion<ClassTemplateDecl *,
98                          ClassTemplatePartialSpecializationDecl *> Result
99         = ClassSpec->getSpecializedTemplateOrPartial();
100       if (Result.is<ClassTemplateDecl *>())
101         Template = Result.get<ClassTemplateDecl *>();
102       else
103         Template = Result.get<ClassTemplatePartialSpecializationDecl *>();
104 
105     } else
106       Template = CXXRecord->getInstantiatedFromMemberClass();
107   } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
108     Template = Function->getPrimaryTemplate();
109     if (!Template)
110       Template = Function->getInstantiatedFromMemberFunction();
111   } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
112     if (Var->isStaticDataMember())
113       Template = Var->getInstantiatedFromStaticDataMember();
114   } else if (const RedeclarableTemplateDecl *Tmpl
115                                         = dyn_cast<RedeclarableTemplateDecl>(D))
116     Template = Tmpl->getInstantiatedFromMemberTemplate();
117 
118   if (!Template)
119     return clang_getNullCursor();
120 
121   return MakeCXCursor(Template, getCursorTU(C));
122 }
123