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/DeclBase.h"
22 #include "clang/AST/DeclObjC.h"
23 #include "clang/Basic/TargetInfo.h"
24 #include "clang/ExtractAPI/API.h"
25 #include "clang/ExtractAPI/ExtractAPIVisitor.h"
26 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
27 #include "clang/Frontend/ASTUnit.h"
28 #include "clang/Frontend/FrontendOptions.h"
29 #include "clang/Index/USRGeneration.h"
30 #include "llvm/ADT/SmallString.h"
31 #include "llvm/Support/CBindingWrapping.h"
32 #include "llvm/Support/Casting.h"
33 #include "llvm/Support/JSON.h"
34 #include "llvm/Support/raw_ostream.h"
36 using namespace clang
;
37 using namespace clang::extractapi
;
40 struct LibClangExtractAPIVisitor
41 : ExtractAPIVisitor
<LibClangExtractAPIVisitor
> {
42 using Base
= ExtractAPIVisitor
<LibClangExtractAPIVisitor
>;
44 LibClangExtractAPIVisitor(ASTContext
&Context
, APISet
&API
)
45 : ExtractAPIVisitor
<LibClangExtractAPIVisitor
>(Context
, API
) {}
47 const RawComment
*fetchRawCommentForDecl(const Decl
*D
) const {
48 if (const auto *Comment
= Base::fetchRawCommentForDecl(D
))
51 return Context
.getRawCommentForAnyRedecl(D
);
54 // We need to visit implementations as well to ensure that when a user clicks
55 // on a method defined only within the implementation that we can still
56 // provide a symbol graph for it.
57 bool VisitObjCImplementationDecl(const ObjCImplementationDecl
*Decl
) {
58 if (!shouldDeclBeIncluded(Decl
))
61 auto *Interface
= Decl
->getClassInterface();
63 if (!VisitObjCInterfaceDecl(Interface
))
67 index::generateUSRForDecl(Interface
, USR
);
69 if (auto *InterfaceRecord
= dyn_cast_if_present
<ObjCInterfaceRecord
>(
70 API
.findRecordForUSR(USR
))) {
71 recordObjCMethods(InterfaceRecord
, Decl
->methods());
72 recordObjCProperties(InterfaceRecord
, Decl
->properties());
73 recordObjCInstanceVariables(InterfaceRecord
, Decl
->ivars());
80 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet
, CXAPISet
)
82 // Visits the Decl D and it's transitive DeclContexts recursively, starting from
83 // the outer-most context. This is guaranteed to visit every Decl we need in the
84 // right order to generate symbol graph information for D.
85 static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor
&Visitor
,
87 if (auto *Parent
= D
->getDeclContext())
88 WalkupFromMostDerivedType(Visitor
, cast
<Decl
>(Parent
));
90 switch (D
->getKind()) {
91 #define ABSTRACT_DECL(DECL)
92 #define DECL(CLASS, BASE) \
94 Visitor.WalkUpFrom##CLASS##Decl(static_cast<CLASS##Decl *>(D)); \
96 #include "clang/AST/DeclNodes.inc"
100 static CXString
GenerateCXStringFromSymbolGraphData(llvm::json::Object Obj
) {
101 llvm::SmallString
<0> BackingString
;
102 llvm::raw_svector_ostream
OS(BackingString
);
103 OS
<< llvm::formatv("{0}", Value(std::move(Obj
)));
104 return cxstring::createDup(BackingString
.str());
107 enum CXErrorCode
clang_createAPISet(CXTranslationUnit tu
, CXAPISet
*out_api
) {
108 if (cxtu::isNotUsableTU(tu
) || !out_api
)
109 return CXError_InvalidArguments
;
111 ASTUnit
*Unit
= cxtu::getASTUnit(tu
);
113 auto &Ctx
= Unit
->getASTContext();
114 auto Lang
= Unit
->getInputKind().getLanguage();
115 APISet
*API
= new APISet(Ctx
.getTargetInfo().getTriple(), Lang
,
116 Unit
->getMainFileName().str());
117 LibClangExtractAPIVisitor
Visitor(Ctx
, *API
);
119 for (auto It
= Unit
->top_level_begin(); It
!= Unit
->top_level_end(); ++It
) {
120 Visitor
.TraverseDecl(*It
);
123 *out_api
= wrap(API
);
124 return CXError_Success
;
127 void clang_disposeAPISet(CXAPISet api
) { delete unwrap(api
); }
129 CXString
clang_getSymbolGraphForUSR(const char *usr
, CXAPISet api
) {
130 auto *API
= unwrap(api
);
132 if (auto SGF
= SymbolGraphSerializer::serializeSingleSymbolSGF(usr
, *API
))
133 return GenerateCXStringFromSymbolGraphData(std::move(*SGF
));
135 return cxstring::createNull();
138 CXString
clang_getSymbolGraphForCursor(CXCursor cursor
) {
139 cursor
= clang_getCursorReferenced(cursor
);
140 CXCursorKind Kind
= clang_getCursorKind(cursor
);
141 if (!clang_isDeclaration(Kind
))
142 return cxstring::createNull();
144 const Decl
*D
= cxcursor::getCursorDecl(cursor
);
147 return cxstring::createNull();
149 CXTranslationUnit TU
= cxcursor::getCursorTU(cursor
);
151 return cxstring::createNull();
153 ASTUnit
*Unit
= cxtu::getASTUnit(TU
);
155 auto &Ctx
= Unit
->getASTContext();
157 auto Lang
= Unit
->getInputKind().getLanguage();
158 APISet
API(Ctx
.getTargetInfo().getTriple(), Lang
,
159 Unit
->getMainFileName().str());
160 LibClangExtractAPIVisitor
Visitor(Ctx
, API
);
162 const Decl
*CanonicalDecl
= D
->getCanonicalDecl();
163 CanonicalDecl
= CanonicalDecl
? CanonicalDecl
: D
;
165 SmallString
<128> USR
;
166 if (index::generateUSRForDecl(CanonicalDecl
, USR
))
167 return cxstring::createNull();
169 WalkupFromMostDerivedType(Visitor
, const_cast<Decl
*>(CanonicalDecl
));
170 auto *Record
= API
.findRecordForUSR(USR
);
173 return cxstring::createNull();
175 for (const auto &Fragment
: Record
->Declaration
.getFragments()) {
176 if (Fragment
.Declaration
)
177 WalkupFromMostDerivedType(Visitor
,
178 const_cast<Decl
*>(Fragment
.Declaration
));
181 if (auto SGF
= SymbolGraphSerializer::serializeSingleSymbolSGF(USR
, API
))
182 return GenerateCXStringFromSymbolGraphData(std::move(*SGF
));
184 return cxstring::createNull();