xref: /llvm-project/clang/tools/libclang/CXExtractAPI.cpp (revision 209a1e8dfdf1c104dd53b50eb196d6bc0dd01659)
1 //===- CXExtractAPI.cpp - libclang APIs for manipulating CXAPISet ---------===//
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 defines all libclang APIs related to manipulation CXAPISet
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "CXCursor.h"
14 #include "CXString.h"
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"
34 
35 using namespace clang;
36 using namespace clang::extractapi;
37 
38 namespace {
39 struct LibClangExtractAPIVisitor
40     : ExtractAPIVisitor<LibClangExtractAPIVisitor> {
41   using Base = ExtractAPIVisitor<LibClangExtractAPIVisitor>;
42 
43   LibClangExtractAPIVisitor(ASTContext &Context, APISet &API)
44       : ExtractAPIVisitor<LibClangExtractAPIVisitor>(Context, API) {}
45 
46   const RawComment *fetchRawCommentForDecl(const Decl *D) const {
47     return Context.getRawCommentForAnyRedecl(D);
48   }
49 
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))
55       return true;
56 
57     const ObjCInterfaceDecl *Interface = Decl->getClassInterface();
58     StringRef Name = Interface->getName();
59     StringRef USR = API.recordUSR(Decl);
60     PresumedLoc Loc =
61         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
62     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
63     DocComment Comment;
64     if (auto *RawComment = fetchRawCommentForDecl(Interface))
65       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
66                                               Context.getDiagnostics());
67 
68     // Build declaration fragments and sub-heading by generating them for the
69     // interface.
70     DeclarationFragments Declaration =
71         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Interface);
72     DeclarationFragments SubHeading =
73         DeclarationFragmentsBuilder::getSubHeading(Decl);
74 
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);
80     }
81 
82     ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface(
83         Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage,
84         Comment, Declaration, SubHeading, SuperClass, isInSystemHeader(Decl));
85 
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());
91 
92     return true;
93   }
94 };
95 } // namespace
96 
97 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet, CXAPISet)
98 
99 static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor,
100                                       Decl *D);
101 
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);
107     return true;
108   }
109   return false;
110 }
111 
112 static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor,
113                                       Decl *D) {
114   switch (D->getKind()) {
115 #define ABSTRACT_DECL(DECL)
116 #define DECL(CLASS, BASE)                                                      \
117   case Decl::CLASS:                                                            \
118     Visitor.WalkUpFrom##CLASS##Decl(static_cast<CLASS##Decl *>(D));            \
119     break;
120 #include "clang/AST/DeclNodes.inc"
121   }
122 
123   for (auto *Parent = D->getDeclContext(); Parent != nullptr;
124        Parent = Parent->getParent()) {
125     if (WalkupParentContext<ObjCContainerDecl>(Parent, Visitor))
126       return;
127     if (WalkupParentContext<TagDecl>(Parent, Visitor))
128       return;
129   }
130 }
131 
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());
137 }
138 
139 enum CXErrorCode clang_createAPISet(CXTranslationUnit tu, CXAPISet *out_api) {
140   if (cxtu::isNotUsableTU(tu) || !out_api)
141     return CXError_InvalidArguments;
142 
143   ASTUnit *Unit = cxtu::getASTUnit(tu);
144 
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);
150 
151   for (auto It = Unit->top_level_begin(); It != Unit->top_level_end(); ++It) {
152     Visitor.TraverseDecl(*It);
153   }
154 
155   *out_api = wrap(API);
156   return CXError_Success;
157 }
158 
159 void clang_disposeAPISet(CXAPISet api) { delete unwrap(api); }
160 
161 CXString clang_getSymbolGraphForUSR(const char *usr, CXAPISet api) {
162   auto *API = unwrap(api);
163 
164   if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(usr, *API))
165     return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
166 
167   return cxstring::createNull();
168 }
169 
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();
175 
176   const Decl *D = cxcursor::getCursorDecl(cursor);
177 
178   if (!D)
179     return cxstring::createNull();
180 
181   CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
182   if (!TU)
183     return cxstring::createNull();
184 
185   ASTUnit *Unit = cxtu::getASTUnit(TU);
186 
187   auto &Ctx = Unit->getASTContext();
188 
189   auto Lang = Unit->getInputKind().getLanguage();
190   APISet API(Ctx.getTargetInfo().getTriple(), Lang,
191              Unit->getMainFileName().str());
192   LibClangExtractAPIVisitor Visitor(Ctx, API);
193 
194   const Decl *CanonicalDecl = D->getCanonicalDecl();
195   CanonicalDecl = CanonicalDecl ? CanonicalDecl : D;
196 
197   SmallString<128> USR;
198   if (index::generateUSRForDecl(CanonicalDecl, USR))
199     return cxstring::createNull();
200 
201   WalkupFromMostDerivedType(Visitor, const_cast<Decl *>(CanonicalDecl));
202   auto *Record = API.findRecordForUSR(USR);
203 
204   if (!Record)
205     return cxstring::createNull();
206 
207   for (const auto &Fragment : Record->Declaration.getFragments()) {
208     if (Fragment.Declaration)
209       WalkupFromMostDerivedType(Visitor,
210                                 const_cast<Decl *>(Fragment.Declaration));
211   }
212 
213   if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API))
214     return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
215 
216   return cxstring::createNull();
217 }
218