1 //===- CXExtractAPI.cpp - libclang APIs for manipulating CXAPISet ---------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines all libclang APIs related to manipulation CXAPISet
11 //===----------------------------------------------------------------------===//
15 #include "CXTranslationUnit.h"
16 #include "clang-c/CXErrorCode.h"
17 #include "clang-c/Documentation.h"
18 #include "clang-c/Index.h"
19 #include "clang-c/Platform.h"
20 #include "clang/AST/Decl.h"
21 #include "clang/AST/DeclObjC.h"
22 #include "clang/Basic/TargetInfo.h"
23 #include "clang/ExtractAPI/API.h"
24 #include "clang/ExtractAPI/ExtractAPIVisitor.h"
25 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
26 #include "clang/Frontend/ASTUnit.h"
27 #include "clang/Frontend/FrontendOptions.h"
28 #include "clang/Index/USRGeneration.h"
29 #include "llvm/ADT/SmallString.h"
30 #include "llvm/Support/CBindingWrapping.h"
31 #include "llvm/Support/Casting.h"
32 #include "llvm/Support/JSON.h"
33 #include "llvm/Support/raw_ostream.h"
35 using namespace clang
;
36 using namespace clang::extractapi
;
39 struct LibClangExtractAPIVisitor
40 : ExtractAPIVisitor
<LibClangExtractAPIVisitor
> {
41 using Base
= ExtractAPIVisitor
<LibClangExtractAPIVisitor
>;
43 LibClangExtractAPIVisitor(ASTContext
&Context
, APISet
&API
)
44 : ExtractAPIVisitor
<LibClangExtractAPIVisitor
>(Context
, API
) {}
46 const RawComment
*fetchRawCommentForDecl(const Decl
*D
) const {
47 return Context
.getRawCommentForAnyRedecl(D
);
50 // We need to visit implementations as well to ensure that when a user clicks
51 // on a method defined only within the implementation that we can still
52 // provide a symbol graph for it.
53 bool VisitObjCImplementationDecl(const ObjCImplementationDecl
*Decl
) {
54 if (!shouldDeclBeIncluded(Decl
))
57 const ObjCInterfaceDecl
*Interface
= Decl
->getClassInterface();
58 StringRef Name
= Interface
->getName();
59 StringRef USR
= API
.recordUSR(Decl
);
61 Context
.getSourceManager().getPresumedLoc(Decl
->getLocation());
62 LinkageInfo Linkage
= Decl
->getLinkageAndVisibility();
64 if (auto *RawComment
= fetchRawCommentForDecl(Interface
))
65 Comment
= RawComment
->getFormattedLines(Context
.getSourceManager(),
66 Context
.getDiagnostics());
68 // Build declaration fragments and sub-heading by generating them for the
70 DeclarationFragments Declaration
=
71 DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Interface
);
72 DeclarationFragments SubHeading
=
73 DeclarationFragmentsBuilder::getSubHeading(Decl
);
75 // Collect super class information.
76 SymbolReference SuperClass
;
77 if (const auto *SuperClassDecl
= Decl
->getSuperClass()) {
78 SuperClass
.Name
= SuperClassDecl
->getObjCRuntimeNameAsString();
79 SuperClass
.USR
= API
.recordUSR(SuperClassDecl
);
82 ObjCInterfaceRecord
*ObjCInterfaceRecord
= API
.addObjCInterface(
83 Name
, USR
, Loc
, AvailabilitySet(Decl
), Linkage
, Comment
, Declaration
,
84 SubHeading
, SuperClass
, isInSystemHeader(Decl
));
86 // Record all methods (selectors). This doesn't include automatically
87 // synthesized property methods.
88 recordObjCMethods(ObjCInterfaceRecord
, Decl
->methods());
89 recordObjCProperties(ObjCInterfaceRecord
, Decl
->properties());
90 recordObjCInstanceVariables(ObjCInterfaceRecord
, Decl
->ivars());
97 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet
, CXAPISet
)
99 static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor
&Visitor
,
102 template <typename DeclTy
>
103 static bool WalkupParentContext(DeclContext
*Parent
,
104 LibClangExtractAPIVisitor
&Visitor
) {
105 if (auto *D
= dyn_cast
<DeclTy
>(Parent
)) {
106 WalkupFromMostDerivedType(Visitor
, D
);
112 static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor
&Visitor
,
114 switch (D
->getKind()) {
115 #define ABSTRACT_DECL(DECL)
116 #define DECL(CLASS, BASE) \
118 Visitor.WalkUpFrom##CLASS##Decl(static_cast<CLASS##Decl *>(D)); \
120 #include "clang/AST/DeclNodes.inc"
123 for (auto *Parent
= D
->getDeclContext(); Parent
!= nullptr;
124 Parent
= Parent
->getParent()) {
125 if (WalkupParentContext
<ObjCContainerDecl
>(Parent
, Visitor
))
127 if (WalkupParentContext
<TagDecl
>(Parent
, Visitor
))
132 static CXString
GenerateCXStringFromSymbolGraphData(llvm::json::Object Obj
) {
133 llvm::SmallString
<0> BackingString
;
134 llvm::raw_svector_ostream
OS(BackingString
);
135 OS
<< Value(std::move(Obj
));
136 return cxstring::createDup(BackingString
.str());
139 enum CXErrorCode
clang_createAPISet(CXTranslationUnit tu
, CXAPISet
*out_api
) {
140 if (cxtu::isNotUsableTU(tu
) || !out_api
)
141 return CXError_InvalidArguments
;
143 ASTUnit
*Unit
= cxtu::getASTUnit(tu
);
145 auto &Ctx
= Unit
->getASTContext();
146 auto Lang
= Unit
->getInputKind().getLanguage();
147 APISet
*API
= new APISet(Ctx
.getTargetInfo().getTriple(), Lang
,
148 Unit
->getMainFileName().str());
149 LibClangExtractAPIVisitor
Visitor(Ctx
, *API
);
151 for (auto It
= Unit
->top_level_begin(); It
!= Unit
->top_level_end(); ++It
) {
152 Visitor
.TraverseDecl(*It
);
155 *out_api
= wrap(API
);
156 return CXError_Success
;
159 void clang_disposeAPISet(CXAPISet api
) { delete unwrap(api
); }
161 CXString
clang_getSymbolGraphForUSR(const char *usr
, CXAPISet api
) {
162 auto *API
= unwrap(api
);
164 if (auto SGF
= SymbolGraphSerializer::serializeSingleSymbolSGF(usr
, *API
))
165 return GenerateCXStringFromSymbolGraphData(std::move(*SGF
));
167 return cxstring::createNull();
170 CXString
clang_getSymbolGraphForCursor(CXCursor cursor
) {
171 cursor
= clang_getCursorReferenced(cursor
);
172 CXCursorKind Kind
= clang_getCursorKind(cursor
);
173 if (!clang_isDeclaration(Kind
))
174 return cxstring::createNull();
176 const Decl
*D
= cxcursor::getCursorDecl(cursor
);
179 return cxstring::createNull();
181 CXTranslationUnit TU
= cxcursor::getCursorTU(cursor
);
183 return cxstring::createNull();
185 ASTUnit
*Unit
= cxtu::getASTUnit(TU
);
187 auto &Ctx
= Unit
->getASTContext();
189 auto Lang
= Unit
->getInputKind().getLanguage();
190 APISet
API(Ctx
.getTargetInfo().getTriple(), Lang
,
191 Unit
->getMainFileName().str());
192 LibClangExtractAPIVisitor
Visitor(Ctx
, API
);
194 const Decl
*CanonicalDecl
= D
->getCanonicalDecl();
195 CanonicalDecl
= CanonicalDecl
? CanonicalDecl
: D
;
197 SmallString
<128> USR
;
198 if (index::generateUSRForDecl(CanonicalDecl
, USR
))
199 return cxstring::createNull();
201 WalkupFromMostDerivedType(Visitor
, const_cast<Decl
*>(CanonicalDecl
));
202 auto *Record
= API
.findRecordForUSR(USR
);
205 return cxstring::createNull();
207 for (const auto &Fragment
: Record
->Declaration
.getFragments()) {
208 if (Fragment
.Declaration
)
209 WalkupFromMostDerivedType(Visitor
,
210 const_cast<Decl
*>(Fragment
.Declaration
));
213 if (auto SGF
= SymbolGraphSerializer::serializeSingleSymbolSGF(USR
, API
))
214 return GenerateCXStringFromSymbolGraphData(std::move(*SGF
));
216 return cxstring::createNull();