brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · c35558e Raw
186 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines all libclang APIs related to manipulation CXAPISet10//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/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"35 36using namespace clang;37using namespace clang::extractapi;38 39namespace {40struct LibClangExtractAPIVisitor41    : ExtractAPIVisitor<LibClangExtractAPIVisitor> {42  using Base = ExtractAPIVisitor<LibClangExtractAPIVisitor>;43 44  LibClangExtractAPIVisitor(ASTContext &Context, APISet &API)45      : ExtractAPIVisitor<LibClangExtractAPIVisitor>(Context, API) {}46 47  const RawComment *fetchRawCommentForDecl(const Decl *D) const {48    if (const auto *Comment = Base::fetchRawCommentForDecl(D))49      return Comment;50 51    return Context.getRawCommentForAnyRedecl(D);52  }53 54  // We need to visit implementations as well to ensure that when a user clicks55  // on a method defined only within the implementation that we can still56  // provide a symbol graph for it.57  bool VisitObjCImplementationDecl(const ObjCImplementationDecl *Decl) {58    if (!shouldDeclBeIncluded(Decl))59      return true;60 61    auto *Interface = Decl->getClassInterface();62 63    if (!VisitObjCInterfaceDecl(Interface))64      return false;65 66    SmallString<128> USR;67    index::generateUSRForDecl(Interface, USR);68 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());74    }75    return true;76  }77};78} // namespace79 80DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet, CXAPISet)81 82// Visits the Decl D and it's transitive DeclContexts recursively, starting from83// the outer-most context. This is guaranteed to visit every Decl we need in the84// right order to generate symbol graph information for D.85static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor,86                                      Decl *D) {87  if (auto *Parent = D->getDeclContext())88    WalkupFromMostDerivedType(Visitor, cast<Decl>(Parent));89 90  switch (D->getKind()) {91#define ABSTRACT_DECL(DECL)92#define DECL(CLASS, BASE)                                                      \93  case Decl::CLASS:                                                            \94    Visitor.WalkUpFrom##CLASS##Decl(static_cast<CLASS##Decl *>(D));            \95    break;96#include "clang/AST/DeclNodes.inc"97  }98}99 100static 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());105}106 107enum CXErrorCode clang_createAPISet(CXTranslationUnit tu, CXAPISet *out_api) {108  if (cxtu::isNotUsableTU(tu) || !out_api)109    return CXError_InvalidArguments;110 111  ASTUnit *Unit = cxtu::getASTUnit(tu);112 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);118 119  for (auto It = Unit->top_level_begin(); It != Unit->top_level_end(); ++It) {120    Visitor.TraverseDecl(*It);121  }122 123  *out_api = wrap(API);124  return CXError_Success;125}126 127void clang_disposeAPISet(CXAPISet api) { delete unwrap(api); }128 129CXString clang_getSymbolGraphForUSR(const char *usr, CXAPISet api) {130  auto *API = unwrap(api);131 132  if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(usr, *API))133    return GenerateCXStringFromSymbolGraphData(std::move(*SGF));134 135  return cxstring::createNull();136}137 138CXString clang_getSymbolGraphForCursor(CXCursor cursor) {139  cursor = clang_getCursorReferenced(cursor);140  CXCursorKind Kind = clang_getCursorKind(cursor);141  if (!clang_isDeclaration(Kind))142    return cxstring::createNull();143 144  const Decl *D = cxcursor::getCursorDecl(cursor);145 146  if (!D)147    return cxstring::createNull();148 149  CXTranslationUnit TU = cxcursor::getCursorTU(cursor);150  if (!TU)151    return cxstring::createNull();152 153  ASTUnit *Unit = cxtu::getASTUnit(TU);154 155  auto &Ctx = Unit->getASTContext();156 157  auto Lang = Unit->getInputKind().getLanguage();158  APISet API(Ctx.getTargetInfo().getTriple(), Lang,159             Unit->getMainFileName().str());160  LibClangExtractAPIVisitor Visitor(Ctx, API);161 162  const Decl *CanonicalDecl = D->getCanonicalDecl();163  CanonicalDecl = CanonicalDecl ? CanonicalDecl : D;164 165  SmallString<128> USR;166  if (index::generateUSRForDecl(CanonicalDecl, USR))167    return cxstring::createNull();168 169  WalkupFromMostDerivedType(Visitor, const_cast<Decl *>(CanonicalDecl));170  auto *Record = API.findRecordForUSR(USR);171 172  if (!Record)173    return cxstring::createNull();174 175  for (const auto &Fragment : Record->Declaration.getFragments()) {176    if (Fragment.Declaration)177      WalkupFromMostDerivedType(Visitor,178                                const_cast<Decl *>(Fragment.Declaration));179  }180 181  if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API))182    return GenerateCXStringFromSymbolGraphData(std::move(*SGF));183 184  return cxstring::createNull();185}186