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
19using namespace clang;
20using namespace clang::cxcursor;
21
22unsigned 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
30enum 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
50enum 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
82CXCursor 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