189f6b26fSZixu Wang //===- ExtractAPI/ExtractAPIConsumer.cpp ------------------------*- C++ -*-===//
289f6b26fSZixu Wang //
389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information.
589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
689f6b26fSZixu Wang //
789f6b26fSZixu Wang //===----------------------------------------------------------------------===//
889f6b26fSZixu Wang ///
989f6b26fSZixu Wang /// \file
1089f6b26fSZixu Wang /// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to
1189f6b26fSZixu Wang /// collect API information.
1289f6b26fSZixu Wang ///
1389f6b26fSZixu Wang //===----------------------------------------------------------------------===//
1489f6b26fSZixu Wang 
1589f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h"
1689f6b26fSZixu Wang #include "clang/AST/ASTContext.h"
1789f6b26fSZixu Wang #include "clang/AST/Decl.h"
1889f6b26fSZixu Wang #include "clang/AST/DeclCXX.h"
1989f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h"
2089f6b26fSZixu Wang #include "clang/AST/RawCommentList.h"
2189f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h"
2289f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h"
2389f6b26fSZixu Wang #include "clang/ExtractAPI/API.h"
2489f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h"
2589f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h"
2689f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h"
2789f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
2889f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h"
2989f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h"
30f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h"
31f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h"
32f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h"
3389f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h"
3489f6b26fSZixu Wang 
3589f6b26fSZixu Wang using namespace clang;
3689f6b26fSZixu Wang using namespace extractapi;
3789f6b26fSZixu Wang 
3889f6b26fSZixu Wang namespace {
3989f6b26fSZixu Wang 
4089f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API
4189f6b26fSZixu Wang /// information.
4289f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
4389f6b26fSZixu Wang public:
4415bf0e56SZixu Wang   ExtractAPIVisitor(ASTContext &Context, Language Lang)
4515bf0e56SZixu Wang       : Context(Context), API(Context.getTargetInfo().getTriple(), Lang) {}
4689f6b26fSZixu Wang 
4789f6b26fSZixu Wang   const APISet &getAPI() const { return API; }
4889f6b26fSZixu Wang 
4989f6b26fSZixu Wang   bool VisitVarDecl(const VarDecl *Decl) {
5089f6b26fSZixu Wang     // Skip function parameters.
5189f6b26fSZixu Wang     if (isa<ParmVarDecl>(Decl))
5289f6b26fSZixu Wang       return true;
5389f6b26fSZixu Wang 
5489f6b26fSZixu Wang     // Skip non-global variables in records (struct/union/class).
5589f6b26fSZixu Wang     if (Decl->getDeclContext()->isRecord())
5689f6b26fSZixu Wang       return true;
5789f6b26fSZixu Wang 
5889f6b26fSZixu Wang     // Skip local variables inside function or method.
5989f6b26fSZixu Wang     if (!Decl->isDefinedOutsideFunctionOrMethod())
6089f6b26fSZixu Wang       return true;
6189f6b26fSZixu Wang 
6289f6b26fSZixu Wang     // If this is a template but not specialization or instantiation, skip.
6389f6b26fSZixu Wang     if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
6489f6b26fSZixu Wang         Decl->getTemplateSpecializationKind() == TSK_Undeclared)
6589f6b26fSZixu Wang       return true;
6689f6b26fSZixu Wang 
6789f6b26fSZixu Wang     // Collect symbol information.
6889f6b26fSZixu Wang     StringRef Name = Decl->getName();
6989f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
7089f6b26fSZixu Wang     PresumedLoc Loc =
7189f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
7289f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
7389f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
7489f6b26fSZixu Wang     DocComment Comment;
7589f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
7689f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
7789f6b26fSZixu Wang                                               Context.getDiagnostics());
7889f6b26fSZixu Wang 
7989f6b26fSZixu Wang     // Build declaration fragments and sub-heading for the variable.
8089f6b26fSZixu Wang     DeclarationFragments Declaration =
8189f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
8289f6b26fSZixu Wang     DeclarationFragments SubHeading =
8389f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
8489f6b26fSZixu Wang 
8589f6b26fSZixu Wang     // Add the global variable record to the API set.
8689f6b26fSZixu Wang     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
8789f6b26fSZixu Wang                      Declaration, SubHeading);
8889f6b26fSZixu Wang     return true;
8989f6b26fSZixu Wang   }
9089f6b26fSZixu Wang 
9189f6b26fSZixu Wang   bool VisitFunctionDecl(const FunctionDecl *Decl) {
9289f6b26fSZixu Wang     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
9389f6b26fSZixu Wang       // Skip member function in class templates.
9489f6b26fSZixu Wang       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
9589f6b26fSZixu Wang         return true;
9689f6b26fSZixu Wang 
9789f6b26fSZixu Wang       // Skip methods in records.
9889f6b26fSZixu Wang       for (auto P : Context.getParents(*Method)) {
9989f6b26fSZixu Wang         if (P.get<CXXRecordDecl>())
10089f6b26fSZixu Wang           return true;
10189f6b26fSZixu Wang       }
10289f6b26fSZixu Wang 
10389f6b26fSZixu Wang       // Skip ConstructorDecl and DestructorDecl.
10489f6b26fSZixu Wang       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
10589f6b26fSZixu Wang         return true;
10689f6b26fSZixu Wang     }
10789f6b26fSZixu Wang 
10889f6b26fSZixu Wang     // Skip templated functions.
10989f6b26fSZixu Wang     switch (Decl->getTemplatedKind()) {
11089f6b26fSZixu Wang     case FunctionDecl::TK_NonTemplate:
11189f6b26fSZixu Wang       break;
11289f6b26fSZixu Wang     case FunctionDecl::TK_MemberSpecialization:
11389f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplateSpecialization:
11489f6b26fSZixu Wang       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
11589f6b26fSZixu Wang         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
11689f6b26fSZixu Wang           return true;
11789f6b26fSZixu Wang       }
11889f6b26fSZixu Wang       break;
11989f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplate:
12089f6b26fSZixu Wang     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
12189f6b26fSZixu Wang       return true;
12289f6b26fSZixu Wang     }
12389f6b26fSZixu Wang 
12489f6b26fSZixu Wang     // Collect symbol information.
12589f6b26fSZixu Wang     StringRef Name = Decl->getName();
12689f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
12789f6b26fSZixu Wang     PresumedLoc Loc =
12889f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
12989f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
13089f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
13189f6b26fSZixu Wang     DocComment Comment;
13289f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
13389f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
13489f6b26fSZixu Wang                                               Context.getDiagnostics());
13589f6b26fSZixu Wang 
13689f6b26fSZixu Wang     // Build declaration fragments, sub-heading, and signature of the function.
13789f6b26fSZixu Wang     DeclarationFragments Declaration =
13889f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
13989f6b26fSZixu Wang     DeclarationFragments SubHeading =
14089f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
14189f6b26fSZixu Wang     FunctionSignature Signature =
14289f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
14389f6b26fSZixu Wang 
14489f6b26fSZixu Wang     // Add the function record to the API set.
14589f6b26fSZixu Wang     API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration,
14689f6b26fSZixu Wang                     SubHeading, Signature);
14789f6b26fSZixu Wang     return true;
14889f6b26fSZixu Wang   }
14989f6b26fSZixu Wang 
15071b4c226SZixu Wang   bool VisitEnumDecl(const EnumDecl *Decl) {
15171b4c226SZixu Wang     if (!Decl->isComplete())
15271b4c226SZixu Wang       return true;
15371b4c226SZixu Wang 
15471b4c226SZixu Wang     // Skip forward declaration.
15571b4c226SZixu Wang     if (!Decl->isThisDeclarationADefinition())
15671b4c226SZixu Wang       return true;
15771b4c226SZixu Wang 
15871b4c226SZixu Wang     // Collect symbol information.
15971b4c226SZixu Wang     StringRef Name = Decl->getName();
16071b4c226SZixu Wang     StringRef USR = API.recordUSR(Decl);
16171b4c226SZixu Wang     PresumedLoc Loc =
16271b4c226SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
16371b4c226SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
16471b4c226SZixu Wang     DocComment Comment;
16571b4c226SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
16671b4c226SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
16771b4c226SZixu Wang                                               Context.getDiagnostics());
16871b4c226SZixu Wang 
16971b4c226SZixu Wang     // Build declaration fragments and sub-heading for the enum.
17071b4c226SZixu Wang     DeclarationFragments Declaration =
17171b4c226SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
17271b4c226SZixu Wang     DeclarationFragments SubHeading =
17371b4c226SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
17471b4c226SZixu Wang 
17571b4c226SZixu Wang     EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
17671b4c226SZixu Wang                                          Declaration, SubHeading);
17771b4c226SZixu Wang 
17871b4c226SZixu Wang     // Now collect information about the enumerators in this enum.
17971b4c226SZixu Wang     recordEnumConstants(EnumRecord, Decl->enumerators());
18071b4c226SZixu Wang 
18171b4c226SZixu Wang     return true;
18271b4c226SZixu Wang   }
18371b4c226SZixu Wang 
1845bb5704cSZixu Wang   bool VisitRecordDecl(const RecordDecl *Decl) {
1855bb5704cSZixu Wang     if (!Decl->isCompleteDefinition())
1865bb5704cSZixu Wang       return true;
1875bb5704cSZixu Wang 
1885bb5704cSZixu Wang     // Skip C++ structs/classes/unions
1895bb5704cSZixu Wang     // TODO: support C++ records
1905bb5704cSZixu Wang     if (isa<CXXRecordDecl>(Decl))
1915bb5704cSZixu Wang       return true;
1925bb5704cSZixu Wang 
1935bb5704cSZixu Wang     // Collect symbol information.
1945bb5704cSZixu Wang     StringRef Name = Decl->getName();
1955bb5704cSZixu Wang     StringRef USR = API.recordUSR(Decl);
1965bb5704cSZixu Wang     PresumedLoc Loc =
1975bb5704cSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
1985bb5704cSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
1995bb5704cSZixu Wang     DocComment Comment;
2005bb5704cSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2015bb5704cSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2025bb5704cSZixu Wang                                               Context.getDiagnostics());
2035bb5704cSZixu Wang 
2045bb5704cSZixu Wang     // Build declaration fragments and sub-heading for the struct.
2055bb5704cSZixu Wang     DeclarationFragments Declaration =
2065bb5704cSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
2075bb5704cSZixu Wang     DeclarationFragments SubHeading =
2085bb5704cSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2095bb5704cSZixu Wang 
2105bb5704cSZixu Wang     StructRecord *StructRecord = API.addStruct(
2115bb5704cSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
2125bb5704cSZixu Wang 
2135bb5704cSZixu Wang     // Now collect information about the fields in this struct.
2145bb5704cSZixu Wang     recordStructFields(StructRecord, Decl->fields());
2155bb5704cSZixu Wang 
2165bb5704cSZixu Wang     return true;
2175bb5704cSZixu Wang   }
2185bb5704cSZixu Wang 
2199b36e126SZixu Wang   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
2209b36e126SZixu Wang     // Skip forward declaration for classes (@class)
2219b36e126SZixu Wang     if (!Decl->isThisDeclarationADefinition())
2229b36e126SZixu Wang       return true;
2239b36e126SZixu Wang 
2249b36e126SZixu Wang     // Collect symbol information.
2259b36e126SZixu Wang     StringRef Name = Decl->getName();
2269b36e126SZixu Wang     StringRef USR = API.recordUSR(Decl);
2279b36e126SZixu Wang     PresumedLoc Loc =
2289b36e126SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2299b36e126SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2309b36e126SZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
2319b36e126SZixu Wang     DocComment Comment;
2329b36e126SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2339b36e126SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2349b36e126SZixu Wang                                               Context.getDiagnostics());
2359b36e126SZixu Wang 
2369b36e126SZixu Wang     // Build declaration fragments and sub-heading for the interface.
2379b36e126SZixu Wang     DeclarationFragments Declaration =
2389b36e126SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
2399b36e126SZixu Wang     DeclarationFragments SubHeading =
2409b36e126SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2419b36e126SZixu Wang 
2429b36e126SZixu Wang     // Collect super class information.
2439b36e126SZixu Wang     SymbolReference SuperClass;
2449b36e126SZixu Wang     if (const auto *SuperClassDecl = Decl->getSuperClass()) {
2459b36e126SZixu Wang       SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
2469b36e126SZixu Wang       SuperClass.USR = API.recordUSR(SuperClassDecl);
2479b36e126SZixu Wang     }
2489b36e126SZixu Wang 
2499b36e126SZixu Wang     ObjCInterfaceRecord *ObjCInterfaceRecord =
2509b36e126SZixu Wang         API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
2519b36e126SZixu Wang                              Declaration, SubHeading, SuperClass);
2529b36e126SZixu Wang 
2539b36e126SZixu Wang     // Record all methods (selectors). This doesn't include automatically
2549b36e126SZixu Wang     // synthesized property methods.
2559b36e126SZixu Wang     recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
2569b36e126SZixu Wang     recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
2579b36e126SZixu Wang     recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
2589b36e126SZixu Wang     recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
2599b36e126SZixu Wang 
2609b36e126SZixu Wang     return true;
2619b36e126SZixu Wang   }
2629b36e126SZixu Wang 
263*d1d34bafSZixu Wang   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
264*d1d34bafSZixu Wang     // Skip forward declaration for protocols (@protocol).
265*d1d34bafSZixu Wang     if (!Decl->isThisDeclarationADefinition())
266*d1d34bafSZixu Wang       return true;
267*d1d34bafSZixu Wang 
268*d1d34bafSZixu Wang     // Collect symbol information.
269*d1d34bafSZixu Wang     StringRef Name = Decl->getName();
270*d1d34bafSZixu Wang     StringRef USR = API.recordUSR(Decl);
271*d1d34bafSZixu Wang     PresumedLoc Loc =
272*d1d34bafSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
273*d1d34bafSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
274*d1d34bafSZixu Wang     DocComment Comment;
275*d1d34bafSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
276*d1d34bafSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
277*d1d34bafSZixu Wang                                               Context.getDiagnostics());
278*d1d34bafSZixu Wang 
279*d1d34bafSZixu Wang     // Build declaration fragments and sub-heading for the protocol.
280*d1d34bafSZixu Wang     DeclarationFragments Declaration =
281*d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
282*d1d34bafSZixu Wang     DeclarationFragments SubHeading =
283*d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
284*d1d34bafSZixu Wang 
285*d1d34bafSZixu Wang     ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
286*d1d34bafSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
287*d1d34bafSZixu Wang 
288*d1d34bafSZixu Wang     recordObjCMethods(ObjCProtocolRecord, Decl->methods());
289*d1d34bafSZixu Wang     recordObjCProperties(ObjCProtocolRecord, Decl->properties());
290*d1d34bafSZixu Wang     recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
291*d1d34bafSZixu Wang 
292*d1d34bafSZixu Wang     return true;
293*d1d34bafSZixu Wang   }
294*d1d34bafSZixu Wang 
29589f6b26fSZixu Wang private:
29689f6b26fSZixu Wang   /// Get availability information of the declaration \p D.
29789f6b26fSZixu Wang   AvailabilityInfo getAvailability(const Decl *D) const {
29889f6b26fSZixu Wang     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
29989f6b26fSZixu Wang 
30089f6b26fSZixu Wang     AvailabilityInfo Availability;
30189f6b26fSZixu Wang     // Collect availability attributes from all redeclarations.
30289f6b26fSZixu Wang     for (const auto *RD : D->redecls()) {
30389f6b26fSZixu Wang       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
30489f6b26fSZixu Wang         if (A->getPlatform()->getName() != PlatformName)
30589f6b26fSZixu Wang           continue;
30689f6b26fSZixu Wang         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
30789f6b26fSZixu Wang                                         A->getObsoleted(), A->getUnavailable(),
30889f6b26fSZixu Wang                                         /* UnconditionallyDeprecated */ false,
30989f6b26fSZixu Wang                                         /* UnconditionallyUnavailable */ false);
31089f6b26fSZixu Wang         break;
31189f6b26fSZixu Wang       }
31289f6b26fSZixu Wang 
31389f6b26fSZixu Wang       if (const auto *A = RD->getAttr<UnavailableAttr>())
31489f6b26fSZixu Wang         if (!A->isImplicit()) {
31589f6b26fSZixu Wang           Availability.Unavailable = true;
31689f6b26fSZixu Wang           Availability.UnconditionallyUnavailable = true;
31789f6b26fSZixu Wang         }
31889f6b26fSZixu Wang 
31989f6b26fSZixu Wang       if (const auto *A = RD->getAttr<DeprecatedAttr>())
32089f6b26fSZixu Wang         if (!A->isImplicit())
32189f6b26fSZixu Wang           Availability.UnconditionallyDeprecated = true;
32289f6b26fSZixu Wang     }
32389f6b26fSZixu Wang 
32489f6b26fSZixu Wang     return Availability;
32589f6b26fSZixu Wang   }
32689f6b26fSZixu Wang 
32771b4c226SZixu Wang   /// Collect API information for the enum constants and associate with the
32871b4c226SZixu Wang   /// parent enum.
32971b4c226SZixu Wang   void recordEnumConstants(EnumRecord *EnumRecord,
33071b4c226SZixu Wang                            const EnumDecl::enumerator_range Constants) {
33171b4c226SZixu Wang     for (const auto *Constant : Constants) {
33271b4c226SZixu Wang       // Collect symbol information.
33371b4c226SZixu Wang       StringRef Name = Constant->getName();
33471b4c226SZixu Wang       StringRef USR = API.recordUSR(Constant);
33571b4c226SZixu Wang       PresumedLoc Loc =
33671b4c226SZixu Wang           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
33771b4c226SZixu Wang       AvailabilityInfo Availability = getAvailability(Constant);
33871b4c226SZixu Wang       DocComment Comment;
33971b4c226SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
34071b4c226SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
34171b4c226SZixu Wang                                                 Context.getDiagnostics());
34271b4c226SZixu Wang 
34371b4c226SZixu Wang       // Build declaration fragments and sub-heading for the enum constant.
34471b4c226SZixu Wang       DeclarationFragments Declaration =
34571b4c226SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
34671b4c226SZixu Wang       DeclarationFragments SubHeading =
34771b4c226SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Constant);
34871b4c226SZixu Wang 
34971b4c226SZixu Wang       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
35071b4c226SZixu Wang                           Declaration, SubHeading);
35171b4c226SZixu Wang     }
35271b4c226SZixu Wang   }
35371b4c226SZixu Wang 
3545bb5704cSZixu Wang   /// Collect API information for the struct fields and associate with the
3555bb5704cSZixu Wang   /// parent struct.
3565bb5704cSZixu Wang   void recordStructFields(StructRecord *StructRecord,
3575bb5704cSZixu Wang                           const RecordDecl::field_range Fields) {
3585bb5704cSZixu Wang     for (const auto *Field : Fields) {
3595bb5704cSZixu Wang       // Collect symbol information.
3605bb5704cSZixu Wang       StringRef Name = Field->getName();
3615bb5704cSZixu Wang       StringRef USR = API.recordUSR(Field);
3625bb5704cSZixu Wang       PresumedLoc Loc =
3635bb5704cSZixu Wang           Context.getSourceManager().getPresumedLoc(Field->getLocation());
3645bb5704cSZixu Wang       AvailabilityInfo Availability = getAvailability(Field);
3655bb5704cSZixu Wang       DocComment Comment;
3665bb5704cSZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
3675bb5704cSZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3685bb5704cSZixu Wang                                                 Context.getDiagnostics());
3695bb5704cSZixu Wang 
3705bb5704cSZixu Wang       // Build declaration fragments and sub-heading for the struct field.
3715bb5704cSZixu Wang       DeclarationFragments Declaration =
3725bb5704cSZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Field);
3735bb5704cSZixu Wang       DeclarationFragments SubHeading =
3745bb5704cSZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Field);
3755bb5704cSZixu Wang 
3765bb5704cSZixu Wang       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
3775bb5704cSZixu Wang                          Declaration, SubHeading);
3785bb5704cSZixu Wang     }
3795bb5704cSZixu Wang   }
3805bb5704cSZixu Wang 
3819b36e126SZixu Wang   /// Collect API information for the Objective-C methods and associate with the
3829b36e126SZixu Wang   /// parent container.
3839b36e126SZixu Wang   void recordObjCMethods(ObjCContainerRecord *Container,
3849b36e126SZixu Wang                          const ObjCContainerDecl::method_range Methods) {
3859b36e126SZixu Wang     for (const auto *Method : Methods) {
3869b36e126SZixu Wang       // Don't record selectors for properties.
3879b36e126SZixu Wang       if (Method->isPropertyAccessor())
3889b36e126SZixu Wang         continue;
3899b36e126SZixu Wang 
3909b36e126SZixu Wang       StringRef Name = API.copyString(Method->getSelector().getAsString());
3919b36e126SZixu Wang       StringRef USR = API.recordUSR(Method);
3929b36e126SZixu Wang       PresumedLoc Loc =
3939b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Method->getLocation());
3949b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Method);
3959b36e126SZixu Wang       DocComment Comment;
3969b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
3979b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3989b36e126SZixu Wang                                                 Context.getDiagnostics());
3999b36e126SZixu Wang 
4009b36e126SZixu Wang       // Build declaration fragments, sub-heading, and signature for the method.
4019b36e126SZixu Wang       DeclarationFragments Declaration =
4029b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
4039b36e126SZixu Wang       DeclarationFragments SubHeading =
4049b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Method);
4059b36e126SZixu Wang       FunctionSignature Signature =
4069b36e126SZixu Wang           DeclarationFragmentsBuilder::getFunctionSignature(Method);
4079b36e126SZixu Wang 
4089b36e126SZixu Wang       API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
4099b36e126SZixu Wang                         Declaration, SubHeading, Signature,
4109b36e126SZixu Wang                         Method->isInstanceMethod());
4119b36e126SZixu Wang     }
4129b36e126SZixu Wang   }
4139b36e126SZixu Wang 
4149b36e126SZixu Wang   void recordObjCProperties(ObjCContainerRecord *Container,
4159b36e126SZixu Wang                             const ObjCContainerDecl::prop_range Properties) {
4169b36e126SZixu Wang     for (const auto *Property : Properties) {
4179b36e126SZixu Wang       StringRef Name = Property->getName();
4189b36e126SZixu Wang       StringRef USR = API.recordUSR(Property);
4199b36e126SZixu Wang       PresumedLoc Loc =
4209b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Property->getLocation());
4219b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Property);
4229b36e126SZixu Wang       DocComment Comment;
4239b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
4249b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
4259b36e126SZixu Wang                                                 Context.getDiagnostics());
4269b36e126SZixu Wang 
4279b36e126SZixu Wang       // Build declaration fragments and sub-heading for the property.
4289b36e126SZixu Wang       DeclarationFragments Declaration =
4299b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
4309b36e126SZixu Wang       DeclarationFragments SubHeading =
4319b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Property);
4329b36e126SZixu Wang 
4339b36e126SZixu Wang       StringRef GetterName =
4349b36e126SZixu Wang           API.copyString(Property->getGetterName().getAsString());
4359b36e126SZixu Wang       StringRef SetterName =
4369b36e126SZixu Wang           API.copyString(Property->getSetterName().getAsString());
4379b36e126SZixu Wang 
4389b36e126SZixu Wang       // Get the attributes for property.
4399b36e126SZixu Wang       unsigned Attributes = ObjCPropertyRecord::NoAttr;
4409b36e126SZixu Wang       if (Property->getPropertyAttributes() &
4419b36e126SZixu Wang           ObjCPropertyAttribute::kind_readonly)
4429b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::ReadOnly;
4439b36e126SZixu Wang       if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
4449b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::Class;
4459b36e126SZixu Wang 
4469b36e126SZixu Wang       API.addObjCProperty(
4479b36e126SZixu Wang           Container, Name, USR, Loc, Availability, Comment, Declaration,
4489b36e126SZixu Wang           SubHeading,
4499b36e126SZixu Wang           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
4509b36e126SZixu Wang           GetterName, SetterName, Property->isOptional());
4519b36e126SZixu Wang     }
4529b36e126SZixu Wang   }
4539b36e126SZixu Wang 
4549b36e126SZixu Wang   void recordObjCInstanceVariables(
4559b36e126SZixu Wang       ObjCContainerRecord *Container,
4569b36e126SZixu Wang       const llvm::iterator_range<
4579b36e126SZixu Wang           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
4589b36e126SZixu Wang           Ivars) {
4599b36e126SZixu Wang     for (const auto *Ivar : Ivars) {
4609b36e126SZixu Wang       StringRef Name = Ivar->getName();
4619b36e126SZixu Wang       StringRef USR = API.recordUSR(Ivar);
4629b36e126SZixu Wang       PresumedLoc Loc =
4639b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
4649b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Ivar);
4659b36e126SZixu Wang       DocComment Comment;
4669b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
4679b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
4689b36e126SZixu Wang                                                 Context.getDiagnostics());
4699b36e126SZixu Wang 
4709b36e126SZixu Wang       // Build declaration fragments and sub-heading for the instance variable.
4719b36e126SZixu Wang       DeclarationFragments Declaration =
4729b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
4739b36e126SZixu Wang       DeclarationFragments SubHeading =
4749b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Ivar);
4759b36e126SZixu Wang 
4769b36e126SZixu Wang       ObjCInstanceVariableRecord::AccessControl Access =
4779b36e126SZixu Wang           Ivar->getCanonicalAccessControl();
4789b36e126SZixu Wang 
4799b36e126SZixu Wang       API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
4809b36e126SZixu Wang                                   Comment, Declaration, SubHeading, Access);
4819b36e126SZixu Wang     }
4829b36e126SZixu Wang   }
4839b36e126SZixu Wang 
4849b36e126SZixu Wang   void recordObjCProtocols(ObjCContainerRecord *Container,
4859b36e126SZixu Wang                            ObjCInterfaceDecl::protocol_range Protocols) {
4869b36e126SZixu Wang     for (const auto *Protocol : Protocols)
4879b36e126SZixu Wang       Container->Protocols.emplace_back(Protocol->getName(),
4889b36e126SZixu Wang                                         API.recordUSR(Protocol));
4899b36e126SZixu Wang   }
4909b36e126SZixu Wang 
49189f6b26fSZixu Wang   ASTContext &Context;
49289f6b26fSZixu Wang   APISet API;
49389f6b26fSZixu Wang };
49489f6b26fSZixu Wang 
49589f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer {
49689f6b26fSZixu Wang public:
49715bf0e56SZixu Wang   ExtractAPIConsumer(ASTContext &Context, StringRef ProductName, Language Lang,
4985ef2ec7eSDaniel Grumberg                      std::unique_ptr<raw_pwrite_stream> OS)
49915bf0e56SZixu Wang       : Visitor(Context, Lang), ProductName(ProductName), OS(std::move(OS)) {}
50089f6b26fSZixu Wang 
50189f6b26fSZixu Wang   void HandleTranslationUnit(ASTContext &Context) override {
50289f6b26fSZixu Wang     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
50389f6b26fSZixu Wang     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
50489f6b26fSZixu Wang 
50589f6b26fSZixu Wang     // Setup a SymbolGraphSerializer to write out collected API information in
50689f6b26fSZixu Wang     // the Symbol Graph format.
50789f6b26fSZixu Wang     // FIXME: Make the kind of APISerializer configurable.
5085ef2ec7eSDaniel Grumberg     SymbolGraphSerializer SGSerializer(Visitor.getAPI(), ProductName);
50989f6b26fSZixu Wang     SGSerializer.serialize(*OS);
51089f6b26fSZixu Wang   }
51189f6b26fSZixu Wang 
51289f6b26fSZixu Wang private:
51389f6b26fSZixu Wang   ExtractAPIVisitor Visitor;
5145ef2ec7eSDaniel Grumberg   std::string ProductName;
51589f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS;
51689f6b26fSZixu Wang };
51789f6b26fSZixu Wang 
51889f6b26fSZixu Wang } // namespace
51989f6b26fSZixu Wang 
52089f6b26fSZixu Wang std::unique_ptr<ASTConsumer>
52189f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
52289f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
52389f6b26fSZixu Wang   if (!OS)
52489f6b26fSZixu Wang     return nullptr;
5255ef2ec7eSDaniel Grumberg   return std::make_unique<ExtractAPIConsumer>(
5265ef2ec7eSDaniel Grumberg       CI.getASTContext(), CI.getInvocation().getFrontendOpts().ProductName,
52715bf0e56SZixu Wang       CI.getFrontendOpts().Inputs.back().getKind().getLanguage(),
52889f6b26fSZixu Wang       std::move(OS));
52989f6b26fSZixu Wang }
53089f6b26fSZixu Wang 
531f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
532f833aab0SDaniel Grumberg   auto &Inputs = CI.getFrontendOpts().Inputs;
533f833aab0SDaniel Grumberg   if (Inputs.empty())
534f833aab0SDaniel Grumberg     return true;
535f833aab0SDaniel Grumberg 
536f833aab0SDaniel Grumberg   auto Kind = Inputs[0].getKind();
537f833aab0SDaniel Grumberg 
538f833aab0SDaniel Grumberg   // Convert the header file inputs into a single input buffer.
539f833aab0SDaniel Grumberg   SmallString<256> HeaderContents;
540f833aab0SDaniel Grumberg   for (const FrontendInputFile &FIF : Inputs) {
541f833aab0SDaniel Grumberg     if (Kind.isObjectiveC())
542f833aab0SDaniel Grumberg       HeaderContents += "#import";
543f833aab0SDaniel Grumberg     else
544f833aab0SDaniel Grumberg       HeaderContents += "#include";
545f833aab0SDaniel Grumberg     HeaderContents += " \"";
546f833aab0SDaniel Grumberg     HeaderContents += FIF.getFile();
547f833aab0SDaniel Grumberg     HeaderContents += "\"\n";
548f833aab0SDaniel Grumberg   }
549f833aab0SDaniel Grumberg 
550f833aab0SDaniel Grumberg   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
551f833aab0SDaniel Grumberg                                                 getInputBufferName());
552f833aab0SDaniel Grumberg 
553f833aab0SDaniel Grumberg   // Set that buffer up as our "real" input in the CompilerInstance.
554f833aab0SDaniel Grumberg   Inputs.clear();
555f833aab0SDaniel Grumberg   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
556f833aab0SDaniel Grumberg 
557f833aab0SDaniel Grumberg   return true;
558f833aab0SDaniel Grumberg }
559f833aab0SDaniel Grumberg 
56089f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream>
56189f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
56289f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS =
56389f6b26fSZixu Wang       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
56489f6b26fSZixu Wang                                  /*RemoveFileOnSignal=*/false);
56589f6b26fSZixu Wang   if (!OS)
56689f6b26fSZixu Wang     return nullptr;
56789f6b26fSZixu Wang   return OS;
56889f6b26fSZixu Wang }
569