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