/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/libclang/CXExtractAPI.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 19 | : ExtractAPIVisitor<LibClangExtractAPIVisitor>(Context, API) {} |
45 | | |
46 | 111 | const RawComment *fetchRawCommentForDecl(const Decl *D) const { |
47 | 111 | return Context.getRawCommentForAnyRedecl(D); |
48 | 111 | } |
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 | 0 | bool VisitObjCImplementationDecl(const ObjCImplementationDecl *Decl) { |
54 | 0 | if (!shouldDeclBeIncluded(Decl)) |
55 | 0 | return true; |
56 | | |
57 | 0 | const ObjCInterfaceDecl *Interface = Decl->getClassInterface(); |
58 | 0 | StringRef Name = Interface->getName(); |
59 | 0 | StringRef USR = API.recordUSR(Decl); |
60 | 0 | PresumedLoc Loc = |
61 | 0 | Context.getSourceManager().getPresumedLoc(Decl->getLocation()); |
62 | 0 | LinkageInfo Linkage = Decl->getLinkageAndVisibility(); |
63 | 0 | DocComment Comment; |
64 | 0 | if (auto *RawComment = fetchRawCommentForDecl(Interface)) |
65 | 0 | Comment = RawComment->getFormattedLines(Context.getSourceManager(), |
66 | 0 | Context.getDiagnostics()); |
67 | | |
68 | | // Build declaration fragments and sub-heading by generating them for the |
69 | | // interface. |
70 | 0 | DeclarationFragments Declaration = |
71 | 0 | DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Interface); |
72 | 0 | DeclarationFragments SubHeading = |
73 | 0 | DeclarationFragmentsBuilder::getSubHeading(Decl); |
74 | | |
75 | | // Collect super class information. |
76 | 0 | SymbolReference SuperClass; |
77 | 0 | if (const auto *SuperClassDecl = Decl->getSuperClass()) { |
78 | 0 | SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); |
79 | 0 | SuperClass.USR = API.recordUSR(SuperClassDecl); |
80 | 0 | } |
81 | |
|
82 | 0 | ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( |
83 | 0 | Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration, |
84 | 0 | SubHeading, SuperClass, isInSystemHeader(Decl)); |
85 | | |
86 | | // Record all methods (selectors). This doesn't include automatically |
87 | | // synthesized property methods. |
88 | 0 | recordObjCMethods(ObjCInterfaceRecord, Decl->methods()); |
89 | 0 | recordObjCProperties(ObjCInterfaceRecord, Decl->properties()); |
90 | 0 | recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars()); |
91 | |
|
92 | 0 | return true; |
93 | 0 | } |
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 | 33 | LibClangExtractAPIVisitor &Visitor) { |
105 | 33 | if (auto *D = dyn_cast<DeclTy>(Parent)) { |
106 | 6 | WalkupFromMostDerivedType(Visitor, D); |
107 | 6 | return true; |
108 | 6 | } |
109 | 27 | return false; |
110 | 33 | } CXExtractAPI.cpp:bool WalkupParentContext<clang::ObjCContainerDecl>(clang::DeclContext*, (anonymous namespace)::LibClangExtractAPIVisitor&) Line | Count | Source | 104 | 19 | LibClangExtractAPIVisitor &Visitor) { | 105 | 19 | if (auto *D = dyn_cast<DeclTy>(Parent)) { | 106 | 5 | WalkupFromMostDerivedType(Visitor, D); | 107 | 5 | return true; | 108 | 5 | } | 109 | 14 | return false; | 110 | 19 | } |
CXExtractAPI.cpp:bool WalkupParentContext<clang::TagDecl>(clang::DeclContext*, (anonymous namespace)::LibClangExtractAPIVisitor&) Line | Count | Source | 104 | 14 | LibClangExtractAPIVisitor &Visitor) { | 105 | 14 | if (auto *D = dyn_cast<DeclTy>(Parent)) { | 106 | 1 | WalkupFromMostDerivedType(Visitor, D); | 107 | 1 | return true; | 108 | 1 | } | 109 | 13 | return false; | 110 | 14 | } |
|
111 | | |
112 | | static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor, |
113 | 19 | Decl *D) { |
114 | 19 | switch (D->getKind()) { |
115 | 0 | #define ABSTRACT_DECL(DECL) |
116 | 0 | #define DECL(CLASS, BASE) \ |
117 | 19 | case Decl::CLASS: \ |
118 | 19 | Visitor.WalkUpFrom##CLASS##Decl(static_cast<CLASS##Decl *>(D)); \ |
119 | 19 | break; |
120 | 19 | #include "clang/AST/DeclNodes.inc"0 |
121 | 19 | } |
122 | | |
123 | 32 | for (auto *Parent = D->getDeclContext(); 19 Parent != nullptr; |
124 | 19 | Parent = Parent->getParent()13 ) { |
125 | 19 | if (WalkupParentContext<ObjCContainerDecl>(Parent, Visitor)) |
126 | 5 | return; |
127 | 14 | if (WalkupParentContext<TagDecl>(Parent, Visitor)) |
128 | 1 | return; |
129 | 14 | } |
130 | 19 | } |
131 | | |
132 | 19 | static CXString GenerateCXStringFromSymbolGraphData(llvm::json::Object Obj) { |
133 | 19 | llvm::SmallString<0> BackingString; |
134 | 19 | llvm::raw_svector_ostream OS(BackingString); |
135 | 19 | OS << Value(std::move(Obj)); |
136 | 19 | return cxstring::createDup(BackingString.str()); |
137 | 19 | } |
138 | | |
139 | 9 | enum CXErrorCode clang_createAPISet(CXTranslationUnit tu, CXAPISet *out_api) { |
140 | 9 | if (cxtu::isNotUsableTU(tu) || !out_api) |
141 | 0 | return CXError_InvalidArguments; |
142 | | |
143 | 9 | ASTUnit *Unit = cxtu::getASTUnit(tu); |
144 | | |
145 | 9 | auto &Ctx = Unit->getASTContext(); |
146 | 9 | auto Lang = Unit->getInputKind().getLanguage(); |
147 | 9 | APISet *API = new APISet(Ctx.getTargetInfo().getTriple(), Lang, |
148 | 9 | Unit->getMainFileName().str()); |
149 | 9 | LibClangExtractAPIVisitor Visitor(Ctx, *API); |
150 | | |
151 | 45 | for (auto It = Unit->top_level_begin(); It != Unit->top_level_end(); ++It36 ) { |
152 | 36 | Visitor.TraverseDecl(*It); |
153 | 36 | } |
154 | | |
155 | 9 | *out_api = wrap(API); |
156 | 9 | return CXError_Success; |
157 | 9 | } |
158 | | |
159 | 9 | void clang_disposeAPISet(CXAPISet api) { delete unwrap(api); } |
160 | | |
161 | 9 | CXString clang_getSymbolGraphForUSR(const char *usr, CXAPISet api) { |
162 | 9 | auto *API = unwrap(api); |
163 | | |
164 | 9 | if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(usr, *API)) |
165 | 9 | return GenerateCXStringFromSymbolGraphData(std::move(*SGF)); |
166 | | |
167 | 0 | return cxstring::createNull(); |
168 | 9 | } |
169 | | |
170 | 10 | CXString clang_getSymbolGraphForCursor(CXCursor cursor) { |
171 | 10 | cursor = clang_getCursorReferenced(cursor); |
172 | 10 | CXCursorKind Kind = clang_getCursorKind(cursor); |
173 | 10 | if (!clang_isDeclaration(Kind)) |
174 | 0 | return cxstring::createNull(); |
175 | | |
176 | 10 | const Decl *D = cxcursor::getCursorDecl(cursor); |
177 | | |
178 | 10 | if (!D) |
179 | 0 | return cxstring::createNull(); |
180 | | |
181 | 10 | CXTranslationUnit TU = cxcursor::getCursorTU(cursor); |
182 | 10 | if (!TU) |
183 | 0 | return cxstring::createNull(); |
184 | | |
185 | 10 | ASTUnit *Unit = cxtu::getASTUnit(TU); |
186 | | |
187 | 10 | auto &Ctx = Unit->getASTContext(); |
188 | | |
189 | 10 | auto Lang = Unit->getInputKind().getLanguage(); |
190 | 10 | APISet API(Ctx.getTargetInfo().getTriple(), Lang, |
191 | 10 | Unit->getMainFileName().str()); |
192 | 10 | LibClangExtractAPIVisitor Visitor(Ctx, API); |
193 | | |
194 | 10 | const Decl *CanonicalDecl = D->getCanonicalDecl(); |
195 | 10 | CanonicalDecl = CanonicalDecl ? CanonicalDecl : D0 ; |
196 | | |
197 | 10 | SmallString<128> USR; |
198 | 10 | if (index::generateUSRForDecl(CanonicalDecl, USR)) |
199 | 0 | return cxstring::createNull(); |
200 | | |
201 | 10 | WalkupFromMostDerivedType(Visitor, const_cast<Decl *>(CanonicalDecl)); |
202 | 10 | auto *Record = API.findRecordForUSR(USR); |
203 | | |
204 | 10 | if (!Record) |
205 | 0 | return cxstring::createNull(); |
206 | | |
207 | 59 | for (const auto &Fragment : Record->Declaration.getFragments())10 { |
208 | 59 | if (Fragment.Declaration) |
209 | 3 | WalkupFromMostDerivedType(Visitor, |
210 | 3 | const_cast<Decl *>(Fragment.Declaration)); |
211 | 59 | } |
212 | | |
213 | 10 | if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API)) |
214 | 10 | return GenerateCXStringFromSymbolGraphData(std::move(*SGF)); |
215 | | |
216 | 0 | return cxstring::createNull(); |
217 | 10 | } |