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 
159fc45ca0SDaniel Grumberg #include "TypedefUnderlyingTypeResolver.h"
1689f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h"
1789f6b26fSZixu Wang #include "clang/AST/ASTContext.h"
1889f6b26fSZixu Wang #include "clang/AST/Decl.h"
1989f6b26fSZixu Wang #include "clang/AST/DeclCXX.h"
2089f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h"
2189f6b26fSZixu Wang #include "clang/AST/RawCommentList.h"
2289f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h"
2389f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h"
2489f6b26fSZixu Wang #include "clang/ExtractAPI/API.h"
2589f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h"
2689f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h"
2789f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h"
2889f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
2989f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h"
3089f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h"
31f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h"
32529a0570SDaniel Grumberg #include "clang/Lex/MacroInfo.h"
33529a0570SDaniel Grumberg #include "clang/Lex/PPCallbacks.h"
34529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h"
35529a0570SDaniel Grumberg #include "llvm/ADT/STLExtras.h"
36f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h"
37f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h"
3889f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h"
3989f6b26fSZixu Wang 
4089f6b26fSZixu Wang using namespace clang;
4189f6b26fSZixu Wang using namespace extractapi;
4289f6b26fSZixu Wang 
4389f6b26fSZixu Wang namespace {
4489f6b26fSZixu Wang 
459fc45ca0SDaniel Grumberg StringRef getTypedefName(const TagDecl *Decl) {
469fc45ca0SDaniel Grumberg   if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
479fc45ca0SDaniel Grumberg     return TypedefDecl->getName();
489fc45ca0SDaniel Grumberg 
499fc45ca0SDaniel Grumberg   return {};
509fc45ca0SDaniel Grumberg }
519fc45ca0SDaniel Grumberg 
5289f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API
5389f6b26fSZixu Wang /// information.
5489f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
5589f6b26fSZixu Wang public:
56a9909d23SDaniel Grumberg   ExtractAPIVisitor(ASTContext &Context, APISet &API)
57a9909d23SDaniel Grumberg       : Context(Context), API(API) {}
5889f6b26fSZixu Wang 
5989f6b26fSZixu Wang   const APISet &getAPI() const { return API; }
6089f6b26fSZixu Wang 
6189f6b26fSZixu Wang   bool VisitVarDecl(const VarDecl *Decl) {
6289f6b26fSZixu Wang     // Skip function parameters.
6389f6b26fSZixu Wang     if (isa<ParmVarDecl>(Decl))
6489f6b26fSZixu Wang       return true;
6589f6b26fSZixu Wang 
6689f6b26fSZixu Wang     // Skip non-global variables in records (struct/union/class).
6789f6b26fSZixu Wang     if (Decl->getDeclContext()->isRecord())
6889f6b26fSZixu Wang       return true;
6989f6b26fSZixu Wang 
7089f6b26fSZixu Wang     // Skip local variables inside function or method.
7189f6b26fSZixu Wang     if (!Decl->isDefinedOutsideFunctionOrMethod())
7289f6b26fSZixu Wang       return true;
7389f6b26fSZixu Wang 
7489f6b26fSZixu Wang     // If this is a template but not specialization or instantiation, skip.
7589f6b26fSZixu Wang     if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
7689f6b26fSZixu Wang         Decl->getTemplateSpecializationKind() == TSK_Undeclared)
7789f6b26fSZixu Wang       return true;
7889f6b26fSZixu Wang 
7989f6b26fSZixu Wang     // Collect symbol information.
8089f6b26fSZixu Wang     StringRef Name = Decl->getName();
8189f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
8289f6b26fSZixu Wang     PresumedLoc Loc =
8389f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
8489f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
8589f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
8689f6b26fSZixu Wang     DocComment Comment;
8789f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
8889f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
8989f6b26fSZixu Wang                                               Context.getDiagnostics());
9089f6b26fSZixu Wang 
9189f6b26fSZixu Wang     // Build declaration fragments and sub-heading for the variable.
9289f6b26fSZixu Wang     DeclarationFragments Declaration =
9389f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
9489f6b26fSZixu Wang     DeclarationFragments SubHeading =
9589f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
9689f6b26fSZixu Wang 
9789f6b26fSZixu Wang     // Add the global variable record to the API set.
9889f6b26fSZixu Wang     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
9989f6b26fSZixu Wang                      Declaration, SubHeading);
10089f6b26fSZixu Wang     return true;
10189f6b26fSZixu Wang   }
10289f6b26fSZixu Wang 
10389f6b26fSZixu Wang   bool VisitFunctionDecl(const FunctionDecl *Decl) {
10489f6b26fSZixu Wang     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
10589f6b26fSZixu Wang       // Skip member function in class templates.
10689f6b26fSZixu Wang       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
10789f6b26fSZixu Wang         return true;
10889f6b26fSZixu Wang 
10989f6b26fSZixu Wang       // Skip methods in records.
11089f6b26fSZixu Wang       for (auto P : Context.getParents(*Method)) {
11189f6b26fSZixu Wang         if (P.get<CXXRecordDecl>())
11289f6b26fSZixu Wang           return true;
11389f6b26fSZixu Wang       }
11489f6b26fSZixu Wang 
11589f6b26fSZixu Wang       // Skip ConstructorDecl and DestructorDecl.
11689f6b26fSZixu Wang       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
11789f6b26fSZixu Wang         return true;
11889f6b26fSZixu Wang     }
11989f6b26fSZixu Wang 
12089f6b26fSZixu Wang     // Skip templated functions.
12189f6b26fSZixu Wang     switch (Decl->getTemplatedKind()) {
12289f6b26fSZixu Wang     case FunctionDecl::TK_NonTemplate:
12389f6b26fSZixu Wang       break;
12489f6b26fSZixu Wang     case FunctionDecl::TK_MemberSpecialization:
12589f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplateSpecialization:
12689f6b26fSZixu Wang       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
12789f6b26fSZixu Wang         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
12889f6b26fSZixu Wang           return true;
12989f6b26fSZixu Wang       }
13089f6b26fSZixu Wang       break;
13189f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplate:
13289f6b26fSZixu Wang     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
13389f6b26fSZixu Wang       return true;
13489f6b26fSZixu Wang     }
13589f6b26fSZixu Wang 
13689f6b26fSZixu Wang     // Collect symbol information.
13789f6b26fSZixu Wang     StringRef Name = Decl->getName();
13889f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
13989f6b26fSZixu Wang     PresumedLoc Loc =
14089f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
14189f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
14289f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
14389f6b26fSZixu Wang     DocComment Comment;
14489f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
14589f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
14689f6b26fSZixu Wang                                               Context.getDiagnostics());
14789f6b26fSZixu Wang 
14889f6b26fSZixu Wang     // Build declaration fragments, sub-heading, and signature of the function.
14989f6b26fSZixu Wang     DeclarationFragments Declaration =
15089f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
15189f6b26fSZixu Wang     DeclarationFragments SubHeading =
15289f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
15389f6b26fSZixu Wang     FunctionSignature Signature =
15489f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
15589f6b26fSZixu Wang 
15689f6b26fSZixu Wang     // Add the function record to the API set.
15789f6b26fSZixu Wang     API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration,
15889f6b26fSZixu Wang                     SubHeading, Signature);
15989f6b26fSZixu Wang     return true;
16089f6b26fSZixu Wang   }
16189f6b26fSZixu Wang 
16271b4c226SZixu Wang   bool VisitEnumDecl(const EnumDecl *Decl) {
16371b4c226SZixu Wang     if (!Decl->isComplete())
16471b4c226SZixu Wang       return true;
16571b4c226SZixu Wang 
16671b4c226SZixu Wang     // Skip forward declaration.
16771b4c226SZixu Wang     if (!Decl->isThisDeclarationADefinition())
16871b4c226SZixu Wang       return true;
16971b4c226SZixu Wang 
17071b4c226SZixu Wang     // Collect symbol information.
17171b4c226SZixu Wang     StringRef Name = Decl->getName();
1729fc45ca0SDaniel Grumberg     if (Name.empty())
1739fc45ca0SDaniel Grumberg       Name = getTypedefName(Decl);
17471b4c226SZixu Wang     StringRef USR = API.recordUSR(Decl);
17571b4c226SZixu Wang     PresumedLoc Loc =
17671b4c226SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
17771b4c226SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
17871b4c226SZixu Wang     DocComment Comment;
17971b4c226SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
18071b4c226SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
18171b4c226SZixu Wang                                               Context.getDiagnostics());
18271b4c226SZixu Wang 
18371b4c226SZixu Wang     // Build declaration fragments and sub-heading for the enum.
18471b4c226SZixu Wang     DeclarationFragments Declaration =
18571b4c226SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
18671b4c226SZixu Wang     DeclarationFragments SubHeading =
18771b4c226SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
18871b4c226SZixu Wang 
18971b4c226SZixu Wang     EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
19071b4c226SZixu Wang                                          Declaration, SubHeading);
19171b4c226SZixu Wang 
19271b4c226SZixu Wang     // Now collect information about the enumerators in this enum.
19371b4c226SZixu Wang     recordEnumConstants(EnumRecord, Decl->enumerators());
19471b4c226SZixu Wang 
19571b4c226SZixu Wang     return true;
19671b4c226SZixu Wang   }
19771b4c226SZixu Wang 
1985bb5704cSZixu Wang   bool VisitRecordDecl(const RecordDecl *Decl) {
1995bb5704cSZixu Wang     if (!Decl->isCompleteDefinition())
2005bb5704cSZixu Wang       return true;
2015bb5704cSZixu Wang 
2025bb5704cSZixu Wang     // Skip C++ structs/classes/unions
2035bb5704cSZixu Wang     // TODO: support C++ records
2045bb5704cSZixu Wang     if (isa<CXXRecordDecl>(Decl))
2055bb5704cSZixu Wang       return true;
2065bb5704cSZixu Wang 
2075bb5704cSZixu Wang     // Collect symbol information.
2085bb5704cSZixu Wang     StringRef Name = Decl->getName();
2099fc45ca0SDaniel Grumberg     if (Name.empty())
2109fc45ca0SDaniel Grumberg       Name = getTypedefName(Decl);
2115bb5704cSZixu Wang     StringRef USR = API.recordUSR(Decl);
2125bb5704cSZixu Wang     PresumedLoc Loc =
2135bb5704cSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2145bb5704cSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2155bb5704cSZixu Wang     DocComment Comment;
2165bb5704cSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2175bb5704cSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2185bb5704cSZixu Wang                                               Context.getDiagnostics());
2195bb5704cSZixu Wang 
2205bb5704cSZixu Wang     // Build declaration fragments and sub-heading for the struct.
2215bb5704cSZixu Wang     DeclarationFragments Declaration =
2225bb5704cSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
2235bb5704cSZixu Wang     DeclarationFragments SubHeading =
2245bb5704cSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2255bb5704cSZixu Wang 
2265bb5704cSZixu Wang     StructRecord *StructRecord = API.addStruct(
2275bb5704cSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
2285bb5704cSZixu Wang 
2295bb5704cSZixu Wang     // Now collect information about the fields in this struct.
2305bb5704cSZixu Wang     recordStructFields(StructRecord, Decl->fields());
2315bb5704cSZixu Wang 
2325bb5704cSZixu Wang     return true;
2335bb5704cSZixu Wang   }
2345bb5704cSZixu Wang 
2359b36e126SZixu Wang   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
2369b36e126SZixu Wang     // Skip forward declaration for classes (@class)
2379b36e126SZixu Wang     if (!Decl->isThisDeclarationADefinition())
2389b36e126SZixu Wang       return true;
2399b36e126SZixu Wang 
2409b36e126SZixu Wang     // Collect symbol information.
2419b36e126SZixu Wang     StringRef Name = Decl->getName();
2429b36e126SZixu Wang     StringRef USR = API.recordUSR(Decl);
2439b36e126SZixu Wang     PresumedLoc Loc =
2449b36e126SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2459b36e126SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2469b36e126SZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
2479b36e126SZixu Wang     DocComment Comment;
2489b36e126SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2499b36e126SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2509b36e126SZixu Wang                                               Context.getDiagnostics());
2519b36e126SZixu Wang 
2529b36e126SZixu Wang     // Build declaration fragments and sub-heading for the interface.
2539b36e126SZixu Wang     DeclarationFragments Declaration =
2549b36e126SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
2559b36e126SZixu Wang     DeclarationFragments SubHeading =
2569b36e126SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2579b36e126SZixu Wang 
2589b36e126SZixu Wang     // Collect super class information.
2599b36e126SZixu Wang     SymbolReference SuperClass;
2609b36e126SZixu Wang     if (const auto *SuperClassDecl = Decl->getSuperClass()) {
2619b36e126SZixu Wang       SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
2629b36e126SZixu Wang       SuperClass.USR = API.recordUSR(SuperClassDecl);
2639b36e126SZixu Wang     }
2649b36e126SZixu Wang 
2659b36e126SZixu Wang     ObjCInterfaceRecord *ObjCInterfaceRecord =
2669b36e126SZixu Wang         API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
2679b36e126SZixu Wang                              Declaration, SubHeading, SuperClass);
2689b36e126SZixu Wang 
2699b36e126SZixu Wang     // Record all methods (selectors). This doesn't include automatically
2709b36e126SZixu Wang     // synthesized property methods.
2719b36e126SZixu Wang     recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
2729b36e126SZixu Wang     recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
2739b36e126SZixu Wang     recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
2749b36e126SZixu Wang     recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
2759b36e126SZixu Wang 
2769b36e126SZixu Wang     return true;
2779b36e126SZixu Wang   }
2789b36e126SZixu Wang 
279d1d34bafSZixu Wang   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
280d1d34bafSZixu Wang     // Skip forward declaration for protocols (@protocol).
281d1d34bafSZixu Wang     if (!Decl->isThisDeclarationADefinition())
282d1d34bafSZixu Wang       return true;
283d1d34bafSZixu Wang 
284d1d34bafSZixu Wang     // Collect symbol information.
285d1d34bafSZixu Wang     StringRef Name = Decl->getName();
286d1d34bafSZixu Wang     StringRef USR = API.recordUSR(Decl);
287d1d34bafSZixu Wang     PresumedLoc Loc =
288d1d34bafSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
289d1d34bafSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
290d1d34bafSZixu Wang     DocComment Comment;
291d1d34bafSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
292d1d34bafSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
293d1d34bafSZixu Wang                                               Context.getDiagnostics());
294d1d34bafSZixu Wang 
295d1d34bafSZixu Wang     // Build declaration fragments and sub-heading for the protocol.
296d1d34bafSZixu Wang     DeclarationFragments Declaration =
297d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
298d1d34bafSZixu Wang     DeclarationFragments SubHeading =
299d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
300d1d34bafSZixu Wang 
301d1d34bafSZixu Wang     ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
302d1d34bafSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
303d1d34bafSZixu Wang 
304d1d34bafSZixu Wang     recordObjCMethods(ObjCProtocolRecord, Decl->methods());
305d1d34bafSZixu Wang     recordObjCProperties(ObjCProtocolRecord, Decl->properties());
306d1d34bafSZixu Wang     recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
307d1d34bafSZixu Wang 
308d1d34bafSZixu Wang     return true;
309d1d34bafSZixu Wang   }
310d1d34bafSZixu Wang 
3119fc45ca0SDaniel Grumberg   bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
3129fc45ca0SDaniel Grumberg     // Skip ObjC Type Parameter for now.
3139fc45ca0SDaniel Grumberg     if (isa<ObjCTypeParamDecl>(Decl))
3149fc45ca0SDaniel Grumberg       return true;
3159fc45ca0SDaniel Grumberg 
3169fc45ca0SDaniel Grumberg     if (!Decl->isDefinedOutsideFunctionOrMethod())
3179fc45ca0SDaniel Grumberg       return true;
3189fc45ca0SDaniel Grumberg 
3199fc45ca0SDaniel Grumberg     PresumedLoc Loc =
3209fc45ca0SDaniel Grumberg         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
3219fc45ca0SDaniel Grumberg     StringRef Name = Decl->getName();
3229fc45ca0SDaniel Grumberg     AvailabilityInfo Availability = getAvailability(Decl);
3239fc45ca0SDaniel Grumberg     StringRef USR = API.recordUSR(Decl);
3249fc45ca0SDaniel Grumberg     DocComment Comment;
3259fc45ca0SDaniel Grumberg     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
3269fc45ca0SDaniel Grumberg       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3279fc45ca0SDaniel Grumberg                                               Context.getDiagnostics());
3289fc45ca0SDaniel Grumberg 
3299fc45ca0SDaniel Grumberg     QualType Type = Decl->getUnderlyingType();
3309fc45ca0SDaniel Grumberg     SymbolReference SymRef =
3319fc45ca0SDaniel Grumberg         TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
3329fc45ca0SDaniel Grumberg                                                                          API);
3339fc45ca0SDaniel Grumberg 
3349fc45ca0SDaniel Grumberg     API.addTypedef(Name, USR, Loc, Availability, Comment,
3359fc45ca0SDaniel Grumberg                    DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
3369fc45ca0SDaniel Grumberg                    DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
3379fc45ca0SDaniel Grumberg 
3389fc45ca0SDaniel Grumberg     return true;
3399fc45ca0SDaniel Grumberg   }
3409fc45ca0SDaniel Grumberg 
341*178aad9bSZixu Wang   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
342*178aad9bSZixu Wang     // Collect symbol information.
343*178aad9bSZixu Wang     StringRef Name = Decl->getName();
344*178aad9bSZixu Wang     StringRef USR = API.recordUSR(Decl);
345*178aad9bSZixu Wang     PresumedLoc Loc =
346*178aad9bSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
347*178aad9bSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
348*178aad9bSZixu Wang     DocComment Comment;
349*178aad9bSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
350*178aad9bSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
351*178aad9bSZixu Wang                                               Context.getDiagnostics());
352*178aad9bSZixu Wang     // Build declaration fragments and sub-heading for the category.
353*178aad9bSZixu Wang     DeclarationFragments Declaration =
354*178aad9bSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
355*178aad9bSZixu Wang     DeclarationFragments SubHeading =
356*178aad9bSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
357*178aad9bSZixu Wang 
358*178aad9bSZixu Wang     const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
359*178aad9bSZixu Wang     SymbolReference Interface(InterfaceDecl->getName(),
360*178aad9bSZixu Wang                               API.recordUSR(InterfaceDecl));
361*178aad9bSZixu Wang 
362*178aad9bSZixu Wang     ObjCCategoryRecord *ObjCCategoryRecord =
363*178aad9bSZixu Wang         API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration,
364*178aad9bSZixu Wang                             SubHeading, Interface);
365*178aad9bSZixu Wang 
366*178aad9bSZixu Wang     recordObjCMethods(ObjCCategoryRecord, Decl->methods());
367*178aad9bSZixu Wang     recordObjCProperties(ObjCCategoryRecord, Decl->properties());
368*178aad9bSZixu Wang     recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
369*178aad9bSZixu Wang     recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
370*178aad9bSZixu Wang 
371*178aad9bSZixu Wang     return true;
372*178aad9bSZixu Wang   }
373*178aad9bSZixu Wang 
37489f6b26fSZixu Wang private:
37589f6b26fSZixu Wang   /// Get availability information of the declaration \p D.
37689f6b26fSZixu Wang   AvailabilityInfo getAvailability(const Decl *D) const {
37789f6b26fSZixu Wang     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
37889f6b26fSZixu Wang 
37989f6b26fSZixu Wang     AvailabilityInfo Availability;
38089f6b26fSZixu Wang     // Collect availability attributes from all redeclarations.
38189f6b26fSZixu Wang     for (const auto *RD : D->redecls()) {
38289f6b26fSZixu Wang       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
38389f6b26fSZixu Wang         if (A->getPlatform()->getName() != PlatformName)
38489f6b26fSZixu Wang           continue;
38589f6b26fSZixu Wang         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
38689f6b26fSZixu Wang                                         A->getObsoleted(), A->getUnavailable(),
38789f6b26fSZixu Wang                                         /* UnconditionallyDeprecated */ false,
38889f6b26fSZixu Wang                                         /* UnconditionallyUnavailable */ false);
38989f6b26fSZixu Wang         break;
39089f6b26fSZixu Wang       }
39189f6b26fSZixu Wang 
39289f6b26fSZixu Wang       if (const auto *A = RD->getAttr<UnavailableAttr>())
39389f6b26fSZixu Wang         if (!A->isImplicit()) {
39489f6b26fSZixu Wang           Availability.Unavailable = true;
39589f6b26fSZixu Wang           Availability.UnconditionallyUnavailable = true;
39689f6b26fSZixu Wang         }
39789f6b26fSZixu Wang 
39889f6b26fSZixu Wang       if (const auto *A = RD->getAttr<DeprecatedAttr>())
39989f6b26fSZixu Wang         if (!A->isImplicit())
40089f6b26fSZixu Wang           Availability.UnconditionallyDeprecated = true;
40189f6b26fSZixu Wang     }
40289f6b26fSZixu Wang 
40389f6b26fSZixu Wang     return Availability;
40489f6b26fSZixu Wang   }
40589f6b26fSZixu Wang 
40671b4c226SZixu Wang   /// Collect API information for the enum constants and associate with the
40771b4c226SZixu Wang   /// parent enum.
40871b4c226SZixu Wang   void recordEnumConstants(EnumRecord *EnumRecord,
40971b4c226SZixu Wang                            const EnumDecl::enumerator_range Constants) {
41071b4c226SZixu Wang     for (const auto *Constant : Constants) {
41171b4c226SZixu Wang       // Collect symbol information.
41271b4c226SZixu Wang       StringRef Name = Constant->getName();
41371b4c226SZixu Wang       StringRef USR = API.recordUSR(Constant);
41471b4c226SZixu Wang       PresumedLoc Loc =
41571b4c226SZixu Wang           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
41671b4c226SZixu Wang       AvailabilityInfo Availability = getAvailability(Constant);
41771b4c226SZixu Wang       DocComment Comment;
41871b4c226SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
41971b4c226SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
42071b4c226SZixu Wang                                                 Context.getDiagnostics());
42171b4c226SZixu Wang 
42271b4c226SZixu Wang       // Build declaration fragments and sub-heading for the enum constant.
42371b4c226SZixu Wang       DeclarationFragments Declaration =
42471b4c226SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
42571b4c226SZixu Wang       DeclarationFragments SubHeading =
42671b4c226SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Constant);
42771b4c226SZixu Wang 
42871b4c226SZixu Wang       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
42971b4c226SZixu Wang                           Declaration, SubHeading);
43071b4c226SZixu Wang     }
43171b4c226SZixu Wang   }
43271b4c226SZixu Wang 
4335bb5704cSZixu Wang   /// Collect API information for the struct fields and associate with the
4345bb5704cSZixu Wang   /// parent struct.
4355bb5704cSZixu Wang   void recordStructFields(StructRecord *StructRecord,
4365bb5704cSZixu Wang                           const RecordDecl::field_range Fields) {
4375bb5704cSZixu Wang     for (const auto *Field : Fields) {
4385bb5704cSZixu Wang       // Collect symbol information.
4395bb5704cSZixu Wang       StringRef Name = Field->getName();
4405bb5704cSZixu Wang       StringRef USR = API.recordUSR(Field);
4415bb5704cSZixu Wang       PresumedLoc Loc =
4425bb5704cSZixu Wang           Context.getSourceManager().getPresumedLoc(Field->getLocation());
4435bb5704cSZixu Wang       AvailabilityInfo Availability = getAvailability(Field);
4445bb5704cSZixu Wang       DocComment Comment;
4455bb5704cSZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
4465bb5704cSZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
4475bb5704cSZixu Wang                                                 Context.getDiagnostics());
4485bb5704cSZixu Wang 
4495bb5704cSZixu Wang       // Build declaration fragments and sub-heading for the struct field.
4505bb5704cSZixu Wang       DeclarationFragments Declaration =
4515bb5704cSZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Field);
4525bb5704cSZixu Wang       DeclarationFragments SubHeading =
4535bb5704cSZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Field);
4545bb5704cSZixu Wang 
4555bb5704cSZixu Wang       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
4565bb5704cSZixu Wang                          Declaration, SubHeading);
4575bb5704cSZixu Wang     }
4585bb5704cSZixu Wang   }
4595bb5704cSZixu Wang 
4609b36e126SZixu Wang   /// Collect API information for the Objective-C methods and associate with the
4619b36e126SZixu Wang   /// parent container.
4629b36e126SZixu Wang   void recordObjCMethods(ObjCContainerRecord *Container,
4639b36e126SZixu Wang                          const ObjCContainerDecl::method_range Methods) {
4649b36e126SZixu Wang     for (const auto *Method : Methods) {
4659b36e126SZixu Wang       // Don't record selectors for properties.
4669b36e126SZixu Wang       if (Method->isPropertyAccessor())
4679b36e126SZixu Wang         continue;
4689b36e126SZixu Wang 
4699b36e126SZixu Wang       StringRef Name = API.copyString(Method->getSelector().getAsString());
4709b36e126SZixu Wang       StringRef USR = API.recordUSR(Method);
4719b36e126SZixu Wang       PresumedLoc Loc =
4729b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Method->getLocation());
4739b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Method);
4749b36e126SZixu Wang       DocComment Comment;
4759b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
4769b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
4779b36e126SZixu Wang                                                 Context.getDiagnostics());
4789b36e126SZixu Wang 
4799b36e126SZixu Wang       // Build declaration fragments, sub-heading, and signature for the method.
4809b36e126SZixu Wang       DeclarationFragments Declaration =
4819b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
4829b36e126SZixu Wang       DeclarationFragments SubHeading =
4839b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Method);
4849b36e126SZixu Wang       FunctionSignature Signature =
4859b36e126SZixu Wang           DeclarationFragmentsBuilder::getFunctionSignature(Method);
4869b36e126SZixu Wang 
4879b36e126SZixu Wang       API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
4889b36e126SZixu Wang                         Declaration, SubHeading, Signature,
4899b36e126SZixu Wang                         Method->isInstanceMethod());
4909b36e126SZixu Wang     }
4919b36e126SZixu Wang   }
4929b36e126SZixu Wang 
4939b36e126SZixu Wang   void recordObjCProperties(ObjCContainerRecord *Container,
4949b36e126SZixu Wang                             const ObjCContainerDecl::prop_range Properties) {
4959b36e126SZixu Wang     for (const auto *Property : Properties) {
4969b36e126SZixu Wang       StringRef Name = Property->getName();
4979b36e126SZixu Wang       StringRef USR = API.recordUSR(Property);
4989b36e126SZixu Wang       PresumedLoc Loc =
4999b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Property->getLocation());
5009b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Property);
5019b36e126SZixu Wang       DocComment Comment;
5029b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
5039b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5049b36e126SZixu Wang                                                 Context.getDiagnostics());
5059b36e126SZixu Wang 
5069b36e126SZixu Wang       // Build declaration fragments and sub-heading for the property.
5079b36e126SZixu Wang       DeclarationFragments Declaration =
5089b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
5099b36e126SZixu Wang       DeclarationFragments SubHeading =
5109b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Property);
5119b36e126SZixu Wang 
5129b36e126SZixu Wang       StringRef GetterName =
5139b36e126SZixu Wang           API.copyString(Property->getGetterName().getAsString());
5149b36e126SZixu Wang       StringRef SetterName =
5159b36e126SZixu Wang           API.copyString(Property->getSetterName().getAsString());
5169b36e126SZixu Wang 
5179b36e126SZixu Wang       // Get the attributes for property.
5189b36e126SZixu Wang       unsigned Attributes = ObjCPropertyRecord::NoAttr;
5199b36e126SZixu Wang       if (Property->getPropertyAttributes() &
5209b36e126SZixu Wang           ObjCPropertyAttribute::kind_readonly)
5219b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::ReadOnly;
5229b36e126SZixu Wang       if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
5239b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::Class;
5249b36e126SZixu Wang 
5259b36e126SZixu Wang       API.addObjCProperty(
5269b36e126SZixu Wang           Container, Name, USR, Loc, Availability, Comment, Declaration,
5279b36e126SZixu Wang           SubHeading,
5289b36e126SZixu Wang           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
5299b36e126SZixu Wang           GetterName, SetterName, Property->isOptional());
5309b36e126SZixu Wang     }
5319b36e126SZixu Wang   }
5329b36e126SZixu Wang 
5339b36e126SZixu Wang   void recordObjCInstanceVariables(
5349b36e126SZixu Wang       ObjCContainerRecord *Container,
5359b36e126SZixu Wang       const llvm::iterator_range<
5369b36e126SZixu Wang           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
5379b36e126SZixu Wang           Ivars) {
5389b36e126SZixu Wang     for (const auto *Ivar : Ivars) {
5399b36e126SZixu Wang       StringRef Name = Ivar->getName();
5409b36e126SZixu Wang       StringRef USR = API.recordUSR(Ivar);
5419b36e126SZixu Wang       PresumedLoc Loc =
5429b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
5439b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Ivar);
5449b36e126SZixu Wang       DocComment Comment;
5459b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
5469b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5479b36e126SZixu Wang                                                 Context.getDiagnostics());
5489b36e126SZixu Wang 
5499b36e126SZixu Wang       // Build declaration fragments and sub-heading for the instance variable.
5509b36e126SZixu Wang       DeclarationFragments Declaration =
5519b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
5529b36e126SZixu Wang       DeclarationFragments SubHeading =
5539b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Ivar);
5549b36e126SZixu Wang 
5559b36e126SZixu Wang       ObjCInstanceVariableRecord::AccessControl Access =
5569b36e126SZixu Wang           Ivar->getCanonicalAccessControl();
5579b36e126SZixu Wang 
5589b36e126SZixu Wang       API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
5599b36e126SZixu Wang                                   Comment, Declaration, SubHeading, Access);
5609b36e126SZixu Wang     }
5619b36e126SZixu Wang   }
5629b36e126SZixu Wang 
5639b36e126SZixu Wang   void recordObjCProtocols(ObjCContainerRecord *Container,
5649b36e126SZixu Wang                            ObjCInterfaceDecl::protocol_range Protocols) {
5659b36e126SZixu Wang     for (const auto *Protocol : Protocols)
5669b36e126SZixu Wang       Container->Protocols.emplace_back(Protocol->getName(),
5679b36e126SZixu Wang                                         API.recordUSR(Protocol));
5689b36e126SZixu Wang   }
5699b36e126SZixu Wang 
57089f6b26fSZixu Wang   ASTContext &Context;
571a9909d23SDaniel Grumberg   APISet &API;
57289f6b26fSZixu Wang };
57389f6b26fSZixu Wang 
57489f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer {
57589f6b26fSZixu Wang public:
576a9909d23SDaniel Grumberg   ExtractAPIConsumer(ASTContext &Context, APISet &API)
577a9909d23SDaniel Grumberg       : Visitor(Context, API) {}
57889f6b26fSZixu Wang 
57989f6b26fSZixu Wang   void HandleTranslationUnit(ASTContext &Context) override {
58089f6b26fSZixu Wang     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
58189f6b26fSZixu Wang     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
58289f6b26fSZixu Wang   }
58389f6b26fSZixu Wang 
58489f6b26fSZixu Wang private:
58589f6b26fSZixu Wang   ExtractAPIVisitor Visitor;
58689f6b26fSZixu Wang };
58789f6b26fSZixu Wang 
588529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks {
589529a0570SDaniel Grumberg public:
590529a0570SDaniel Grumberg   MacroCallback(const SourceManager &SM, APISet &API) : SM(SM), API(API) {}
591529a0570SDaniel Grumberg 
592529a0570SDaniel Grumberg   void MacroDefined(const Token &MacroNameToken,
593529a0570SDaniel Grumberg                     const MacroDirective *MD) override {
594529a0570SDaniel Grumberg     auto *MacroInfo = MD->getMacroInfo();
595529a0570SDaniel Grumberg 
596529a0570SDaniel Grumberg     if (MacroInfo->isBuiltinMacro())
597529a0570SDaniel Grumberg       return;
598529a0570SDaniel Grumberg 
599529a0570SDaniel Grumberg     auto SourceLoc = MacroNameToken.getLocation();
600529a0570SDaniel Grumberg     if (SM.isWrittenInBuiltinFile(SourceLoc) ||
601529a0570SDaniel Grumberg         SM.isWrittenInCommandLineFile(SourceLoc))
602529a0570SDaniel Grumberg       return;
603529a0570SDaniel Grumberg 
604529a0570SDaniel Grumberg     PendingMacros.emplace_back(MacroNameToken, MD);
605529a0570SDaniel Grumberg   }
606529a0570SDaniel Grumberg 
607529a0570SDaniel Grumberg   // If a macro gets undefined at some point during preprocessing of the inputs
608529a0570SDaniel Grumberg   // it means that it isn't an exposed API and we should therefore not add a
609529a0570SDaniel Grumberg   // macro definition for it.
610529a0570SDaniel Grumberg   void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD,
611529a0570SDaniel Grumberg                       const MacroDirective *Undef) override {
6128b63622bSDaniel Grumberg     // If this macro wasn't previously defined we don't need to do anything
6138b63622bSDaniel Grumberg     // here.
6148b63622bSDaniel Grumberg     if (!Undef)
6158b63622bSDaniel Grumberg       return;
6168b63622bSDaniel Grumberg 
617529a0570SDaniel Grumberg     llvm::erase_if(PendingMacros, [&MD](const PendingMacro &PM) {
618529a0570SDaniel Grumberg       return MD.getMacroInfo()->getDefinitionLoc() ==
619529a0570SDaniel Grumberg              PM.MD->getMacroInfo()->getDefinitionLoc();
620529a0570SDaniel Grumberg     });
621529a0570SDaniel Grumberg   }
622529a0570SDaniel Grumberg 
623529a0570SDaniel Grumberg   void EndOfMainFile() override {
624529a0570SDaniel Grumberg     for (auto &PM : PendingMacros) {
625529a0570SDaniel Grumberg       // `isUsedForHeaderGuard` is only set when the preprocessor leaves the
626529a0570SDaniel Grumberg       // file so check for it here.
627529a0570SDaniel Grumberg       if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
628529a0570SDaniel Grumberg         continue;
629529a0570SDaniel Grumberg 
630529a0570SDaniel Grumberg       StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
631529a0570SDaniel Grumberg       PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation());
632529a0570SDaniel Grumberg       StringRef USR =
633529a0570SDaniel Grumberg           API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM);
634529a0570SDaniel Grumberg 
635529a0570SDaniel Grumberg       API.addMacroDefinition(
636529a0570SDaniel Grumberg           Name, USR, Loc,
637529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
638529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getSubHeadingForMacro(Name));
639529a0570SDaniel Grumberg     }
640529a0570SDaniel Grumberg 
641529a0570SDaniel Grumberg     PendingMacros.clear();
642529a0570SDaniel Grumberg   }
643529a0570SDaniel Grumberg 
644529a0570SDaniel Grumberg private:
645529a0570SDaniel Grumberg   struct PendingMacro {
646529a0570SDaniel Grumberg     Token MacroNameToken;
647529a0570SDaniel Grumberg     const MacroDirective *MD;
648529a0570SDaniel Grumberg 
649529a0570SDaniel Grumberg     PendingMacro(const Token &MacroNameToken, const MacroDirective *MD)
650529a0570SDaniel Grumberg         : MacroNameToken(MacroNameToken), MD(MD) {}
651529a0570SDaniel Grumberg   };
652529a0570SDaniel Grumberg 
653529a0570SDaniel Grumberg   const SourceManager &SM;
654529a0570SDaniel Grumberg   APISet &API;
655529a0570SDaniel Grumberg   llvm::SmallVector<PendingMacro> PendingMacros;
656529a0570SDaniel Grumberg };
657529a0570SDaniel Grumberg 
65889f6b26fSZixu Wang } // namespace
65989f6b26fSZixu Wang 
66089f6b26fSZixu Wang std::unique_ptr<ASTConsumer>
66189f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
662a9909d23SDaniel Grumberg   OS = CreateOutputFile(CI, InFile);
66389f6b26fSZixu Wang   if (!OS)
66489f6b26fSZixu Wang     return nullptr;
665a9909d23SDaniel Grumberg 
666a9909d23SDaniel Grumberg   ProductName = CI.getFrontendOpts().ProductName;
667a9909d23SDaniel Grumberg 
668a9909d23SDaniel Grumberg   // Now that we have enough information about the language options and the
669a9909d23SDaniel Grumberg   // target triple, let's create the APISet before anyone uses it.
670a9909d23SDaniel Grumberg   API = std::make_unique<APISet>(
671a9909d23SDaniel Grumberg       CI.getTarget().getTriple(),
672a9909d23SDaniel Grumberg       CI.getFrontendOpts().Inputs.back().getKind().getLanguage());
673a9909d23SDaniel Grumberg 
674529a0570SDaniel Grumberg   // Register preprocessor callbacks that will add macro definitions to API.
675529a0570SDaniel Grumberg   CI.getPreprocessor().addPPCallbacks(
676529a0570SDaniel Grumberg       std::make_unique<MacroCallback>(CI.getSourceManager(), *API));
677529a0570SDaniel Grumberg 
678a9909d23SDaniel Grumberg   return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), *API);
67989f6b26fSZixu Wang }
68089f6b26fSZixu Wang 
681f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
682f833aab0SDaniel Grumberg   auto &Inputs = CI.getFrontendOpts().Inputs;
683f833aab0SDaniel Grumberg   if (Inputs.empty())
684f833aab0SDaniel Grumberg     return true;
685f833aab0SDaniel Grumberg 
686f833aab0SDaniel Grumberg   auto Kind = Inputs[0].getKind();
687f833aab0SDaniel Grumberg 
688f833aab0SDaniel Grumberg   // Convert the header file inputs into a single input buffer.
689f833aab0SDaniel Grumberg   SmallString<256> HeaderContents;
690f833aab0SDaniel Grumberg   for (const FrontendInputFile &FIF : Inputs) {
691f833aab0SDaniel Grumberg     if (Kind.isObjectiveC())
692f833aab0SDaniel Grumberg       HeaderContents += "#import";
693f833aab0SDaniel Grumberg     else
694f833aab0SDaniel Grumberg       HeaderContents += "#include";
695f833aab0SDaniel Grumberg     HeaderContents += " \"";
696f833aab0SDaniel Grumberg     HeaderContents += FIF.getFile();
697f833aab0SDaniel Grumberg     HeaderContents += "\"\n";
698f833aab0SDaniel Grumberg   }
699f833aab0SDaniel Grumberg 
700985eaa1aSDaniel Grumberg   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
701f833aab0SDaniel Grumberg                                                 getInputBufferName());
702f833aab0SDaniel Grumberg 
703f833aab0SDaniel Grumberg   // Set that buffer up as our "real" input in the CompilerInstance.
704f833aab0SDaniel Grumberg   Inputs.clear();
705f833aab0SDaniel Grumberg   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
706f833aab0SDaniel Grumberg 
707f833aab0SDaniel Grumberg   return true;
708f833aab0SDaniel Grumberg }
709f833aab0SDaniel Grumberg 
710a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() {
711a9909d23SDaniel Grumberg   if (!OS)
712a9909d23SDaniel Grumberg     return;
713a9909d23SDaniel Grumberg 
714a9909d23SDaniel Grumberg   // Setup a SymbolGraphSerializer to write out collected API information in
715a9909d23SDaniel Grumberg   // the Symbol Graph format.
716a9909d23SDaniel Grumberg   // FIXME: Make the kind of APISerializer configurable.
717a9909d23SDaniel Grumberg   SymbolGraphSerializer SGSerializer(*API, ProductName);
718a9909d23SDaniel Grumberg   SGSerializer.serialize(*OS);
719a9909d23SDaniel Grumberg   OS->flush();
720a9909d23SDaniel Grumberg }
721a9909d23SDaniel Grumberg 
72289f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream>
72389f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
72489f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS =
72589f6b26fSZixu Wang       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
72689f6b26fSZixu Wang                                  /*RemoveFileOnSignal=*/false);
72789f6b26fSZixu Wang   if (!OS)
72889f6b26fSZixu Wang     return nullptr;
72989f6b26fSZixu Wang   return OS;
73089f6b26fSZixu Wang }
731