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"
23*aebe5fc6SDaniel Grumberg #include "clang/Basic/SourceLocation.h"
24*aebe5fc6SDaniel Grumberg #include "clang/Basic/SourceManager.h"
2589f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h"
2689f6b26fSZixu Wang #include "clang/ExtractAPI/API.h"
2789f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h"
2889f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h"
2989f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h"
3089f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
3189f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h"
3289f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h"
33f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h"
34529a0570SDaniel Grumberg #include "clang/Lex/MacroInfo.h"
35529a0570SDaniel Grumberg #include "clang/Lex/PPCallbacks.h"
36*aebe5fc6SDaniel Grumberg #include "clang/Lex/Preprocessor.h"
37529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h"
38*aebe5fc6SDaniel Grumberg #include "llvm/ADT/DenseSet.h"
39529a0570SDaniel Grumberg #include "llvm/ADT/STLExtras.h"
40f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h"
41f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h"
4289f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h"
43*aebe5fc6SDaniel Grumberg #include <memory>
44*aebe5fc6SDaniel Grumberg #include <utility>
4589f6b26fSZixu Wang 
4689f6b26fSZixu Wang using namespace clang;
4789f6b26fSZixu Wang using namespace extractapi;
4889f6b26fSZixu Wang 
4989f6b26fSZixu Wang namespace {
5089f6b26fSZixu Wang 
519fc45ca0SDaniel Grumberg StringRef getTypedefName(const TagDecl *Decl) {
529fc45ca0SDaniel Grumberg   if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
539fc45ca0SDaniel Grumberg     return TypedefDecl->getName();
549fc45ca0SDaniel Grumberg 
559fc45ca0SDaniel Grumberg   return {};
569fc45ca0SDaniel Grumberg }
579fc45ca0SDaniel Grumberg 
58*aebe5fc6SDaniel Grumberg struct LocationFileChecker {
59*aebe5fc6SDaniel Grumberg   bool isLocationInKnownFile(SourceLocation Loc) {
60*aebe5fc6SDaniel Grumberg     // If the loc refers to a macro expansion we need to first get the file
61*aebe5fc6SDaniel Grumberg     // location of the expansion.
62*aebe5fc6SDaniel Grumberg     auto FileLoc = SM.getFileLoc(Loc);
63*aebe5fc6SDaniel Grumberg     FileID FID = SM.getFileID(FileLoc);
64*aebe5fc6SDaniel Grumberg     if (FID.isInvalid())
65*aebe5fc6SDaniel Grumberg       return false;
66*aebe5fc6SDaniel Grumberg 
67*aebe5fc6SDaniel Grumberg     const auto *File = SM.getFileEntryForID(FID);
68*aebe5fc6SDaniel Grumberg     if (!File)
69*aebe5fc6SDaniel Grumberg       return false;
70*aebe5fc6SDaniel Grumberg 
71*aebe5fc6SDaniel Grumberg     if (KnownFileEntries.count(File))
72*aebe5fc6SDaniel Grumberg       return true;
73*aebe5fc6SDaniel Grumberg 
74*aebe5fc6SDaniel Grumberg     return false;
75*aebe5fc6SDaniel Grumberg   }
76*aebe5fc6SDaniel Grumberg 
77*aebe5fc6SDaniel Grumberg   LocationFileChecker(const SourceManager &SM,
78*aebe5fc6SDaniel Grumberg                       const std::vector<std::string> &KnownFiles)
79*aebe5fc6SDaniel Grumberg       : SM(SM) {
80*aebe5fc6SDaniel Grumberg     for (const auto &KnownFilePath : KnownFiles)
81*aebe5fc6SDaniel Grumberg       if (auto FileEntry = SM.getFileManager().getFile(KnownFilePath))
82*aebe5fc6SDaniel Grumberg         KnownFileEntries.insert(*FileEntry);
83*aebe5fc6SDaniel Grumberg   }
84*aebe5fc6SDaniel Grumberg 
85*aebe5fc6SDaniel Grumberg private:
86*aebe5fc6SDaniel Grumberg   const SourceManager &SM;
87*aebe5fc6SDaniel Grumberg   llvm::DenseSet<const FileEntry *> KnownFileEntries;
88*aebe5fc6SDaniel Grumberg };
89*aebe5fc6SDaniel Grumberg 
9089f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API
9189f6b26fSZixu Wang /// information.
9289f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
9389f6b26fSZixu Wang public:
94*aebe5fc6SDaniel Grumberg   ExtractAPIVisitor(ASTContext &Context, LocationFileChecker &LCF, APISet &API)
95*aebe5fc6SDaniel Grumberg       : Context(Context), API(API), LCF(LCF) {}
9689f6b26fSZixu Wang 
9789f6b26fSZixu Wang   const APISet &getAPI() const { return API; }
9889f6b26fSZixu Wang 
9989f6b26fSZixu Wang   bool VisitVarDecl(const VarDecl *Decl) {
10089f6b26fSZixu Wang     // Skip function parameters.
10189f6b26fSZixu Wang     if (isa<ParmVarDecl>(Decl))
10289f6b26fSZixu Wang       return true;
10389f6b26fSZixu Wang 
10489f6b26fSZixu Wang     // Skip non-global variables in records (struct/union/class).
10589f6b26fSZixu Wang     if (Decl->getDeclContext()->isRecord())
10689f6b26fSZixu Wang       return true;
10789f6b26fSZixu Wang 
10889f6b26fSZixu Wang     // Skip local variables inside function or method.
10989f6b26fSZixu Wang     if (!Decl->isDefinedOutsideFunctionOrMethod())
11089f6b26fSZixu Wang       return true;
11189f6b26fSZixu Wang 
11289f6b26fSZixu Wang     // If this is a template but not specialization or instantiation, skip.
11389f6b26fSZixu Wang     if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
11489f6b26fSZixu Wang         Decl->getTemplateSpecializationKind() == TSK_Undeclared)
11589f6b26fSZixu Wang       return true;
11689f6b26fSZixu Wang 
117*aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
118*aebe5fc6SDaniel Grumberg       return true;
119*aebe5fc6SDaniel Grumberg 
12089f6b26fSZixu Wang     // Collect symbol information.
12189f6b26fSZixu Wang     StringRef Name = Decl->getName();
12289f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
12389f6b26fSZixu Wang     PresumedLoc Loc =
12489f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
12589f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
12689f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
12789f6b26fSZixu Wang     DocComment Comment;
12889f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
12989f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
13089f6b26fSZixu Wang                                               Context.getDiagnostics());
13189f6b26fSZixu Wang 
13289f6b26fSZixu Wang     // Build declaration fragments and sub-heading for the variable.
13389f6b26fSZixu Wang     DeclarationFragments Declaration =
13489f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
13589f6b26fSZixu Wang     DeclarationFragments SubHeading =
13689f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
13789f6b26fSZixu Wang 
13889f6b26fSZixu Wang     // Add the global variable record to the API set.
13989f6b26fSZixu Wang     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
14089f6b26fSZixu Wang                      Declaration, SubHeading);
14189f6b26fSZixu Wang     return true;
14289f6b26fSZixu Wang   }
14389f6b26fSZixu Wang 
14489f6b26fSZixu Wang   bool VisitFunctionDecl(const FunctionDecl *Decl) {
14589f6b26fSZixu Wang     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
14689f6b26fSZixu Wang       // Skip member function in class templates.
14789f6b26fSZixu Wang       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
14889f6b26fSZixu Wang         return true;
14989f6b26fSZixu Wang 
15089f6b26fSZixu Wang       // Skip methods in records.
15189f6b26fSZixu Wang       for (auto P : Context.getParents(*Method)) {
15289f6b26fSZixu Wang         if (P.get<CXXRecordDecl>())
15389f6b26fSZixu Wang           return true;
15489f6b26fSZixu Wang       }
15589f6b26fSZixu Wang 
15689f6b26fSZixu Wang       // Skip ConstructorDecl and DestructorDecl.
15789f6b26fSZixu Wang       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
15889f6b26fSZixu Wang         return true;
15989f6b26fSZixu Wang     }
16089f6b26fSZixu Wang 
16189f6b26fSZixu Wang     // Skip templated functions.
16289f6b26fSZixu Wang     switch (Decl->getTemplatedKind()) {
16389f6b26fSZixu Wang     case FunctionDecl::TK_NonTemplate:
16489f6b26fSZixu Wang       break;
16589f6b26fSZixu Wang     case FunctionDecl::TK_MemberSpecialization:
16689f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplateSpecialization:
16789f6b26fSZixu Wang       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
16889f6b26fSZixu Wang         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
16989f6b26fSZixu Wang           return true;
17089f6b26fSZixu Wang       }
17189f6b26fSZixu Wang       break;
17289f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplate:
17389f6b26fSZixu Wang     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
17489f6b26fSZixu Wang       return true;
17589f6b26fSZixu Wang     }
17689f6b26fSZixu Wang 
177*aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
178*aebe5fc6SDaniel Grumberg       return true;
179*aebe5fc6SDaniel Grumberg 
18089f6b26fSZixu Wang     // Collect symbol information.
18189f6b26fSZixu Wang     StringRef Name = Decl->getName();
18289f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
18389f6b26fSZixu Wang     PresumedLoc Loc =
18489f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
18589f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
18689f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
18789f6b26fSZixu Wang     DocComment Comment;
18889f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
18989f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
19089f6b26fSZixu Wang                                               Context.getDiagnostics());
19189f6b26fSZixu Wang 
19289f6b26fSZixu Wang     // Build declaration fragments, sub-heading, and signature of the function.
19389f6b26fSZixu Wang     DeclarationFragments Declaration =
19489f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
19589f6b26fSZixu Wang     DeclarationFragments SubHeading =
19689f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
19789f6b26fSZixu Wang     FunctionSignature Signature =
19889f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
19989f6b26fSZixu Wang 
20089f6b26fSZixu Wang     // Add the function record to the API set.
20189f6b26fSZixu Wang     API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration,
20289f6b26fSZixu Wang                     SubHeading, Signature);
20389f6b26fSZixu Wang     return true;
20489f6b26fSZixu Wang   }
20589f6b26fSZixu Wang 
20671b4c226SZixu Wang   bool VisitEnumDecl(const EnumDecl *Decl) {
20771b4c226SZixu Wang     if (!Decl->isComplete())
20871b4c226SZixu Wang       return true;
20971b4c226SZixu Wang 
21071b4c226SZixu Wang     // Skip forward declaration.
21171b4c226SZixu Wang     if (!Decl->isThisDeclarationADefinition())
21271b4c226SZixu Wang       return true;
21371b4c226SZixu Wang 
214*aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
215*aebe5fc6SDaniel Grumberg       return true;
216*aebe5fc6SDaniel Grumberg 
21771b4c226SZixu Wang     // Collect symbol information.
21871b4c226SZixu Wang     StringRef Name = Decl->getName();
2199fc45ca0SDaniel Grumberg     if (Name.empty())
2209fc45ca0SDaniel Grumberg       Name = getTypedefName(Decl);
22171b4c226SZixu Wang     StringRef USR = API.recordUSR(Decl);
22271b4c226SZixu Wang     PresumedLoc Loc =
22371b4c226SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
22471b4c226SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
22571b4c226SZixu Wang     DocComment Comment;
22671b4c226SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
22771b4c226SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
22871b4c226SZixu Wang                                               Context.getDiagnostics());
22971b4c226SZixu Wang 
23071b4c226SZixu Wang     // Build declaration fragments and sub-heading for the enum.
23171b4c226SZixu Wang     DeclarationFragments Declaration =
23271b4c226SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
23371b4c226SZixu Wang     DeclarationFragments SubHeading =
23471b4c226SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
23571b4c226SZixu Wang 
23671b4c226SZixu Wang     EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
23771b4c226SZixu Wang                                          Declaration, SubHeading);
23871b4c226SZixu Wang 
23971b4c226SZixu Wang     // Now collect information about the enumerators in this enum.
24071b4c226SZixu Wang     recordEnumConstants(EnumRecord, Decl->enumerators());
24171b4c226SZixu Wang 
24271b4c226SZixu Wang     return true;
24371b4c226SZixu Wang   }
24471b4c226SZixu Wang 
2455bb5704cSZixu Wang   bool VisitRecordDecl(const RecordDecl *Decl) {
2465bb5704cSZixu Wang     if (!Decl->isCompleteDefinition())
2475bb5704cSZixu Wang       return true;
2485bb5704cSZixu Wang 
2495bb5704cSZixu Wang     // Skip C++ structs/classes/unions
2505bb5704cSZixu Wang     // TODO: support C++ records
2515bb5704cSZixu Wang     if (isa<CXXRecordDecl>(Decl))
2525bb5704cSZixu Wang       return true;
2535bb5704cSZixu Wang 
254*aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
255*aebe5fc6SDaniel Grumberg       return true;
256*aebe5fc6SDaniel Grumberg 
2575bb5704cSZixu Wang     // Collect symbol information.
2585bb5704cSZixu Wang     StringRef Name = Decl->getName();
2599fc45ca0SDaniel Grumberg     if (Name.empty())
2609fc45ca0SDaniel Grumberg       Name = getTypedefName(Decl);
2615bb5704cSZixu Wang     StringRef USR = API.recordUSR(Decl);
2625bb5704cSZixu Wang     PresumedLoc Loc =
2635bb5704cSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2645bb5704cSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2655bb5704cSZixu Wang     DocComment Comment;
2665bb5704cSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2675bb5704cSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2685bb5704cSZixu Wang                                               Context.getDiagnostics());
2695bb5704cSZixu Wang 
2705bb5704cSZixu Wang     // Build declaration fragments and sub-heading for the struct.
2715bb5704cSZixu Wang     DeclarationFragments Declaration =
2725bb5704cSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
2735bb5704cSZixu Wang     DeclarationFragments SubHeading =
2745bb5704cSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2755bb5704cSZixu Wang 
2765bb5704cSZixu Wang     StructRecord *StructRecord = API.addStruct(
2775bb5704cSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
2785bb5704cSZixu Wang 
2795bb5704cSZixu Wang     // Now collect information about the fields in this struct.
2805bb5704cSZixu Wang     recordStructFields(StructRecord, Decl->fields());
2815bb5704cSZixu Wang 
2825bb5704cSZixu Wang     return true;
2835bb5704cSZixu Wang   }
2845bb5704cSZixu Wang 
2859b36e126SZixu Wang   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
2869b36e126SZixu Wang     // Skip forward declaration for classes (@class)
2879b36e126SZixu Wang     if (!Decl->isThisDeclarationADefinition())
2889b36e126SZixu Wang       return true;
2899b36e126SZixu Wang 
290*aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
291*aebe5fc6SDaniel Grumberg       return true;
292*aebe5fc6SDaniel Grumberg 
2939b36e126SZixu Wang     // Collect symbol information.
2949b36e126SZixu Wang     StringRef Name = Decl->getName();
2959b36e126SZixu Wang     StringRef USR = API.recordUSR(Decl);
2969b36e126SZixu Wang     PresumedLoc Loc =
2979b36e126SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2989b36e126SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2999b36e126SZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
3009b36e126SZixu Wang     DocComment Comment;
3019b36e126SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
3029b36e126SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3039b36e126SZixu Wang                                               Context.getDiagnostics());
3049b36e126SZixu Wang 
3059b36e126SZixu Wang     // Build declaration fragments and sub-heading for the interface.
3069b36e126SZixu Wang     DeclarationFragments Declaration =
3079b36e126SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
3089b36e126SZixu Wang     DeclarationFragments SubHeading =
3099b36e126SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
3109b36e126SZixu Wang 
3119b36e126SZixu Wang     // Collect super class information.
3129b36e126SZixu Wang     SymbolReference SuperClass;
3139b36e126SZixu Wang     if (const auto *SuperClassDecl = Decl->getSuperClass()) {
3149b36e126SZixu Wang       SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
3159b36e126SZixu Wang       SuperClass.USR = API.recordUSR(SuperClassDecl);
3169b36e126SZixu Wang     }
3179b36e126SZixu Wang 
3189b36e126SZixu Wang     ObjCInterfaceRecord *ObjCInterfaceRecord =
3199b36e126SZixu Wang         API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
3209b36e126SZixu Wang                              Declaration, SubHeading, SuperClass);
3219b36e126SZixu Wang 
3229b36e126SZixu Wang     // Record all methods (selectors). This doesn't include automatically
3239b36e126SZixu Wang     // synthesized property methods.
3249b36e126SZixu Wang     recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
3259b36e126SZixu Wang     recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
3269b36e126SZixu Wang     recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
3279b36e126SZixu Wang     recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
3289b36e126SZixu Wang 
3299b36e126SZixu Wang     return true;
3309b36e126SZixu Wang   }
3319b36e126SZixu Wang 
332d1d34bafSZixu Wang   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
333d1d34bafSZixu Wang     // Skip forward declaration for protocols (@protocol).
334d1d34bafSZixu Wang     if (!Decl->isThisDeclarationADefinition())
335d1d34bafSZixu Wang       return true;
336d1d34bafSZixu Wang 
337*aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
338*aebe5fc6SDaniel Grumberg       return true;
339*aebe5fc6SDaniel Grumberg 
340d1d34bafSZixu Wang     // Collect symbol information.
341d1d34bafSZixu Wang     StringRef Name = Decl->getName();
342d1d34bafSZixu Wang     StringRef USR = API.recordUSR(Decl);
343d1d34bafSZixu Wang     PresumedLoc Loc =
344d1d34bafSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
345d1d34bafSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
346d1d34bafSZixu Wang     DocComment Comment;
347d1d34bafSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
348d1d34bafSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
349d1d34bafSZixu Wang                                               Context.getDiagnostics());
350d1d34bafSZixu Wang 
351d1d34bafSZixu Wang     // Build declaration fragments and sub-heading for the protocol.
352d1d34bafSZixu Wang     DeclarationFragments Declaration =
353d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
354d1d34bafSZixu Wang     DeclarationFragments SubHeading =
355d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
356d1d34bafSZixu Wang 
357d1d34bafSZixu Wang     ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
358d1d34bafSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
359d1d34bafSZixu Wang 
360d1d34bafSZixu Wang     recordObjCMethods(ObjCProtocolRecord, Decl->methods());
361d1d34bafSZixu Wang     recordObjCProperties(ObjCProtocolRecord, Decl->properties());
362d1d34bafSZixu Wang     recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
363d1d34bafSZixu Wang 
364d1d34bafSZixu Wang     return true;
365d1d34bafSZixu Wang   }
366d1d34bafSZixu Wang 
3679fc45ca0SDaniel Grumberg   bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
3689fc45ca0SDaniel Grumberg     // Skip ObjC Type Parameter for now.
3699fc45ca0SDaniel Grumberg     if (isa<ObjCTypeParamDecl>(Decl))
3709fc45ca0SDaniel Grumberg       return true;
3719fc45ca0SDaniel Grumberg 
3729fc45ca0SDaniel Grumberg     if (!Decl->isDefinedOutsideFunctionOrMethod())
3739fc45ca0SDaniel Grumberg       return true;
3749fc45ca0SDaniel Grumberg 
375*aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
376*aebe5fc6SDaniel Grumberg       return true;
377*aebe5fc6SDaniel Grumberg 
3789fc45ca0SDaniel Grumberg     PresumedLoc Loc =
3799fc45ca0SDaniel Grumberg         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
3809fc45ca0SDaniel Grumberg     StringRef Name = Decl->getName();
3819fc45ca0SDaniel Grumberg     AvailabilityInfo Availability = getAvailability(Decl);
3829fc45ca0SDaniel Grumberg     StringRef USR = API.recordUSR(Decl);
3839fc45ca0SDaniel Grumberg     DocComment Comment;
3849fc45ca0SDaniel Grumberg     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
3859fc45ca0SDaniel Grumberg       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3869fc45ca0SDaniel Grumberg                                               Context.getDiagnostics());
3879fc45ca0SDaniel Grumberg 
3889fc45ca0SDaniel Grumberg     QualType Type = Decl->getUnderlyingType();
3899fc45ca0SDaniel Grumberg     SymbolReference SymRef =
3909fc45ca0SDaniel Grumberg         TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
3919fc45ca0SDaniel Grumberg                                                                          API);
3929fc45ca0SDaniel Grumberg 
3939fc45ca0SDaniel Grumberg     API.addTypedef(Name, USR, Loc, Availability, Comment,
3949fc45ca0SDaniel Grumberg                    DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
3959fc45ca0SDaniel Grumberg                    DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
3969fc45ca0SDaniel Grumberg 
3979fc45ca0SDaniel Grumberg     return true;
3989fc45ca0SDaniel Grumberg   }
3999fc45ca0SDaniel Grumberg 
400178aad9bSZixu Wang   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
401178aad9bSZixu Wang     // Collect symbol information.
402178aad9bSZixu Wang     StringRef Name = Decl->getName();
403178aad9bSZixu Wang     StringRef USR = API.recordUSR(Decl);
404178aad9bSZixu Wang     PresumedLoc Loc =
405178aad9bSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
406178aad9bSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
407178aad9bSZixu Wang     DocComment Comment;
408178aad9bSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
409178aad9bSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
410178aad9bSZixu Wang                                               Context.getDiagnostics());
411178aad9bSZixu Wang     // Build declaration fragments and sub-heading for the category.
412178aad9bSZixu Wang     DeclarationFragments Declaration =
413178aad9bSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
414178aad9bSZixu Wang     DeclarationFragments SubHeading =
415178aad9bSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
416178aad9bSZixu Wang 
417178aad9bSZixu Wang     const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
418178aad9bSZixu Wang     SymbolReference Interface(InterfaceDecl->getName(),
419178aad9bSZixu Wang                               API.recordUSR(InterfaceDecl));
420178aad9bSZixu Wang 
421178aad9bSZixu Wang     ObjCCategoryRecord *ObjCCategoryRecord =
422178aad9bSZixu Wang         API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration,
423178aad9bSZixu Wang                             SubHeading, Interface);
424178aad9bSZixu Wang 
425178aad9bSZixu Wang     recordObjCMethods(ObjCCategoryRecord, Decl->methods());
426178aad9bSZixu Wang     recordObjCProperties(ObjCCategoryRecord, Decl->properties());
427178aad9bSZixu Wang     recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
428178aad9bSZixu Wang     recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
429178aad9bSZixu Wang 
430178aad9bSZixu Wang     return true;
431178aad9bSZixu Wang   }
432178aad9bSZixu Wang 
43389f6b26fSZixu Wang private:
43489f6b26fSZixu Wang   /// Get availability information of the declaration \p D.
43589f6b26fSZixu Wang   AvailabilityInfo getAvailability(const Decl *D) const {
43689f6b26fSZixu Wang     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
43789f6b26fSZixu Wang 
43889f6b26fSZixu Wang     AvailabilityInfo Availability;
43989f6b26fSZixu Wang     // Collect availability attributes from all redeclarations.
44089f6b26fSZixu Wang     for (const auto *RD : D->redecls()) {
44189f6b26fSZixu Wang       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
44289f6b26fSZixu Wang         if (A->getPlatform()->getName() != PlatformName)
44389f6b26fSZixu Wang           continue;
44489f6b26fSZixu Wang         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
44589f6b26fSZixu Wang                                         A->getObsoleted(), A->getUnavailable(),
44689f6b26fSZixu Wang                                         /* UnconditionallyDeprecated */ false,
44789f6b26fSZixu Wang                                         /* UnconditionallyUnavailable */ false);
44889f6b26fSZixu Wang         break;
44989f6b26fSZixu Wang       }
45089f6b26fSZixu Wang 
45189f6b26fSZixu Wang       if (const auto *A = RD->getAttr<UnavailableAttr>())
45289f6b26fSZixu Wang         if (!A->isImplicit()) {
45389f6b26fSZixu Wang           Availability.Unavailable = true;
45489f6b26fSZixu Wang           Availability.UnconditionallyUnavailable = true;
45589f6b26fSZixu Wang         }
45689f6b26fSZixu Wang 
45789f6b26fSZixu Wang       if (const auto *A = RD->getAttr<DeprecatedAttr>())
45889f6b26fSZixu Wang         if (!A->isImplicit())
45989f6b26fSZixu Wang           Availability.UnconditionallyDeprecated = true;
46089f6b26fSZixu Wang     }
46189f6b26fSZixu Wang 
46289f6b26fSZixu Wang     return Availability;
46389f6b26fSZixu Wang   }
46489f6b26fSZixu Wang 
46571b4c226SZixu Wang   /// Collect API information for the enum constants and associate with the
46671b4c226SZixu Wang   /// parent enum.
46771b4c226SZixu Wang   void recordEnumConstants(EnumRecord *EnumRecord,
46871b4c226SZixu Wang                            const EnumDecl::enumerator_range Constants) {
46971b4c226SZixu Wang     for (const auto *Constant : Constants) {
47071b4c226SZixu Wang       // Collect symbol information.
47171b4c226SZixu Wang       StringRef Name = Constant->getName();
47271b4c226SZixu Wang       StringRef USR = API.recordUSR(Constant);
47371b4c226SZixu Wang       PresumedLoc Loc =
47471b4c226SZixu Wang           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
47571b4c226SZixu Wang       AvailabilityInfo Availability = getAvailability(Constant);
47671b4c226SZixu Wang       DocComment Comment;
47771b4c226SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
47871b4c226SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
47971b4c226SZixu Wang                                                 Context.getDiagnostics());
48071b4c226SZixu Wang 
48171b4c226SZixu Wang       // Build declaration fragments and sub-heading for the enum constant.
48271b4c226SZixu Wang       DeclarationFragments Declaration =
48371b4c226SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
48471b4c226SZixu Wang       DeclarationFragments SubHeading =
48571b4c226SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Constant);
48671b4c226SZixu Wang 
48771b4c226SZixu Wang       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
48871b4c226SZixu Wang                           Declaration, SubHeading);
48971b4c226SZixu Wang     }
49071b4c226SZixu Wang   }
49171b4c226SZixu Wang 
4925bb5704cSZixu Wang   /// Collect API information for the struct fields and associate with the
4935bb5704cSZixu Wang   /// parent struct.
4945bb5704cSZixu Wang   void recordStructFields(StructRecord *StructRecord,
4955bb5704cSZixu Wang                           const RecordDecl::field_range Fields) {
4965bb5704cSZixu Wang     for (const auto *Field : Fields) {
4975bb5704cSZixu Wang       // Collect symbol information.
4985bb5704cSZixu Wang       StringRef Name = Field->getName();
4995bb5704cSZixu Wang       StringRef USR = API.recordUSR(Field);
5005bb5704cSZixu Wang       PresumedLoc Loc =
5015bb5704cSZixu Wang           Context.getSourceManager().getPresumedLoc(Field->getLocation());
5025bb5704cSZixu Wang       AvailabilityInfo Availability = getAvailability(Field);
5035bb5704cSZixu Wang       DocComment Comment;
5045bb5704cSZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
5055bb5704cSZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5065bb5704cSZixu Wang                                                 Context.getDiagnostics());
5075bb5704cSZixu Wang 
5085bb5704cSZixu Wang       // Build declaration fragments and sub-heading for the struct field.
5095bb5704cSZixu Wang       DeclarationFragments Declaration =
5105bb5704cSZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Field);
5115bb5704cSZixu Wang       DeclarationFragments SubHeading =
5125bb5704cSZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Field);
5135bb5704cSZixu Wang 
5145bb5704cSZixu Wang       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
5155bb5704cSZixu Wang                          Declaration, SubHeading);
5165bb5704cSZixu Wang     }
5175bb5704cSZixu Wang   }
5185bb5704cSZixu Wang 
5199b36e126SZixu Wang   /// Collect API information for the Objective-C methods and associate with the
5209b36e126SZixu Wang   /// parent container.
5219b36e126SZixu Wang   void recordObjCMethods(ObjCContainerRecord *Container,
5229b36e126SZixu Wang                          const ObjCContainerDecl::method_range Methods) {
5239b36e126SZixu Wang     for (const auto *Method : Methods) {
5249b36e126SZixu Wang       // Don't record selectors for properties.
5259b36e126SZixu Wang       if (Method->isPropertyAccessor())
5269b36e126SZixu Wang         continue;
5279b36e126SZixu Wang 
5289b36e126SZixu Wang       StringRef Name = API.copyString(Method->getSelector().getAsString());
5299b36e126SZixu Wang       StringRef USR = API.recordUSR(Method);
5309b36e126SZixu Wang       PresumedLoc Loc =
5319b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Method->getLocation());
5329b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Method);
5339b36e126SZixu Wang       DocComment Comment;
5349b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
5359b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5369b36e126SZixu Wang                                                 Context.getDiagnostics());
5379b36e126SZixu Wang 
5389b36e126SZixu Wang       // Build declaration fragments, sub-heading, and signature for the method.
5399b36e126SZixu Wang       DeclarationFragments Declaration =
5409b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
5419b36e126SZixu Wang       DeclarationFragments SubHeading =
5429b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Method);
5439b36e126SZixu Wang       FunctionSignature Signature =
5449b36e126SZixu Wang           DeclarationFragmentsBuilder::getFunctionSignature(Method);
5459b36e126SZixu Wang 
5469b36e126SZixu Wang       API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
5479b36e126SZixu Wang                         Declaration, SubHeading, Signature,
5489b36e126SZixu Wang                         Method->isInstanceMethod());
5499b36e126SZixu Wang     }
5509b36e126SZixu Wang   }
5519b36e126SZixu Wang 
5529b36e126SZixu Wang   void recordObjCProperties(ObjCContainerRecord *Container,
5539b36e126SZixu Wang                             const ObjCContainerDecl::prop_range Properties) {
5549b36e126SZixu Wang     for (const auto *Property : Properties) {
5559b36e126SZixu Wang       StringRef Name = Property->getName();
5569b36e126SZixu Wang       StringRef USR = API.recordUSR(Property);
5579b36e126SZixu Wang       PresumedLoc Loc =
5589b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Property->getLocation());
5599b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Property);
5609b36e126SZixu Wang       DocComment Comment;
5619b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
5629b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5639b36e126SZixu Wang                                                 Context.getDiagnostics());
5649b36e126SZixu Wang 
5659b36e126SZixu Wang       // Build declaration fragments and sub-heading for the property.
5669b36e126SZixu Wang       DeclarationFragments Declaration =
5679b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
5689b36e126SZixu Wang       DeclarationFragments SubHeading =
5699b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Property);
5709b36e126SZixu Wang 
5719b36e126SZixu Wang       StringRef GetterName =
5729b36e126SZixu Wang           API.copyString(Property->getGetterName().getAsString());
5739b36e126SZixu Wang       StringRef SetterName =
5749b36e126SZixu Wang           API.copyString(Property->getSetterName().getAsString());
5759b36e126SZixu Wang 
5769b36e126SZixu Wang       // Get the attributes for property.
5779b36e126SZixu Wang       unsigned Attributes = ObjCPropertyRecord::NoAttr;
5789b36e126SZixu Wang       if (Property->getPropertyAttributes() &
5799b36e126SZixu Wang           ObjCPropertyAttribute::kind_readonly)
5809b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::ReadOnly;
5819b36e126SZixu Wang       if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
5829b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::Class;
5839b36e126SZixu Wang 
5849b36e126SZixu Wang       API.addObjCProperty(
5859b36e126SZixu Wang           Container, Name, USR, Loc, Availability, Comment, Declaration,
5869b36e126SZixu Wang           SubHeading,
5879b36e126SZixu Wang           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
5889b36e126SZixu Wang           GetterName, SetterName, Property->isOptional());
5899b36e126SZixu Wang     }
5909b36e126SZixu Wang   }
5919b36e126SZixu Wang 
5929b36e126SZixu Wang   void recordObjCInstanceVariables(
5939b36e126SZixu Wang       ObjCContainerRecord *Container,
5949b36e126SZixu Wang       const llvm::iterator_range<
5959b36e126SZixu Wang           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
5969b36e126SZixu Wang           Ivars) {
5979b36e126SZixu Wang     for (const auto *Ivar : Ivars) {
5989b36e126SZixu Wang       StringRef Name = Ivar->getName();
5999b36e126SZixu Wang       StringRef USR = API.recordUSR(Ivar);
6009b36e126SZixu Wang       PresumedLoc Loc =
6019b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
6029b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Ivar);
6039b36e126SZixu Wang       DocComment Comment;
6049b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
6059b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
6069b36e126SZixu Wang                                                 Context.getDiagnostics());
6079b36e126SZixu Wang 
6089b36e126SZixu Wang       // Build declaration fragments and sub-heading for the instance variable.
6099b36e126SZixu Wang       DeclarationFragments Declaration =
6109b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
6119b36e126SZixu Wang       DeclarationFragments SubHeading =
6129b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Ivar);
6139b36e126SZixu Wang 
6149b36e126SZixu Wang       ObjCInstanceVariableRecord::AccessControl Access =
6159b36e126SZixu Wang           Ivar->getCanonicalAccessControl();
6169b36e126SZixu Wang 
6179b36e126SZixu Wang       API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
6189b36e126SZixu Wang                                   Comment, Declaration, SubHeading, Access);
6199b36e126SZixu Wang     }
6209b36e126SZixu Wang   }
6219b36e126SZixu Wang 
6229b36e126SZixu Wang   void recordObjCProtocols(ObjCContainerRecord *Container,
6239b36e126SZixu Wang                            ObjCInterfaceDecl::protocol_range Protocols) {
6249b36e126SZixu Wang     for (const auto *Protocol : Protocols)
6259b36e126SZixu Wang       Container->Protocols.emplace_back(Protocol->getName(),
6269b36e126SZixu Wang                                         API.recordUSR(Protocol));
6279b36e126SZixu Wang   }
6289b36e126SZixu Wang 
62989f6b26fSZixu Wang   ASTContext &Context;
630a9909d23SDaniel Grumberg   APISet &API;
631*aebe5fc6SDaniel Grumberg   LocationFileChecker &LCF;
63289f6b26fSZixu Wang };
63389f6b26fSZixu Wang 
63489f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer {
63589f6b26fSZixu Wang public:
636*aebe5fc6SDaniel Grumberg   ExtractAPIConsumer(ASTContext &Context,
637*aebe5fc6SDaniel Grumberg                      std::unique_ptr<LocationFileChecker> LCF, APISet &API)
638*aebe5fc6SDaniel Grumberg       : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {}
63989f6b26fSZixu Wang 
64089f6b26fSZixu Wang   void HandleTranslationUnit(ASTContext &Context) override {
64189f6b26fSZixu Wang     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
64289f6b26fSZixu Wang     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
64389f6b26fSZixu Wang   }
64489f6b26fSZixu Wang 
64589f6b26fSZixu Wang private:
64689f6b26fSZixu Wang   ExtractAPIVisitor Visitor;
647*aebe5fc6SDaniel Grumberg   std::unique_ptr<LocationFileChecker> LCF;
64889f6b26fSZixu Wang };
64989f6b26fSZixu Wang 
650529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks {
651529a0570SDaniel Grumberg public:
652*aebe5fc6SDaniel Grumberg   MacroCallback(const SourceManager &SM, LocationFileChecker &LCF, APISet &API)
653*aebe5fc6SDaniel Grumberg       : SM(SM), LCF(LCF), API(API) {}
654529a0570SDaniel Grumberg 
655529a0570SDaniel Grumberg   void MacroDefined(const Token &MacroNameToken,
656529a0570SDaniel Grumberg                     const MacroDirective *MD) override {
657529a0570SDaniel Grumberg     auto *MacroInfo = MD->getMacroInfo();
658529a0570SDaniel Grumberg 
659529a0570SDaniel Grumberg     if (MacroInfo->isBuiltinMacro())
660529a0570SDaniel Grumberg       return;
661529a0570SDaniel Grumberg 
662529a0570SDaniel Grumberg     auto SourceLoc = MacroNameToken.getLocation();
663529a0570SDaniel Grumberg     if (SM.isWrittenInBuiltinFile(SourceLoc) ||
664529a0570SDaniel Grumberg         SM.isWrittenInCommandLineFile(SourceLoc))
665529a0570SDaniel Grumberg       return;
666529a0570SDaniel Grumberg 
667529a0570SDaniel Grumberg     PendingMacros.emplace_back(MacroNameToken, MD);
668529a0570SDaniel Grumberg   }
669529a0570SDaniel Grumberg 
670529a0570SDaniel Grumberg   // If a macro gets undefined at some point during preprocessing of the inputs
671529a0570SDaniel Grumberg   // it means that it isn't an exposed API and we should therefore not add a
672529a0570SDaniel Grumberg   // macro definition for it.
673529a0570SDaniel Grumberg   void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD,
674529a0570SDaniel Grumberg                       const MacroDirective *Undef) override {
6758b63622bSDaniel Grumberg     // If this macro wasn't previously defined we don't need to do anything
6768b63622bSDaniel Grumberg     // here.
6778b63622bSDaniel Grumberg     if (!Undef)
6788b63622bSDaniel Grumberg       return;
6798b63622bSDaniel Grumberg 
680529a0570SDaniel Grumberg     llvm::erase_if(PendingMacros, [&MD](const PendingMacro &PM) {
681529a0570SDaniel Grumberg       return MD.getMacroInfo()->getDefinitionLoc() ==
682529a0570SDaniel Grumberg              PM.MD->getMacroInfo()->getDefinitionLoc();
683529a0570SDaniel Grumberg     });
684529a0570SDaniel Grumberg   }
685529a0570SDaniel Grumberg 
686529a0570SDaniel Grumberg   void EndOfMainFile() override {
687529a0570SDaniel Grumberg     for (auto &PM : PendingMacros) {
688529a0570SDaniel Grumberg       // `isUsedForHeaderGuard` is only set when the preprocessor leaves the
689529a0570SDaniel Grumberg       // file so check for it here.
690529a0570SDaniel Grumberg       if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
691529a0570SDaniel Grumberg         continue;
692529a0570SDaniel Grumberg 
693*aebe5fc6SDaniel Grumberg       if (!LCF.isLocationInKnownFile(PM.MacroNameToken.getLocation()))
694*aebe5fc6SDaniel Grumberg         continue;
695*aebe5fc6SDaniel Grumberg 
696529a0570SDaniel Grumberg       StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
697529a0570SDaniel Grumberg       PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation());
698529a0570SDaniel Grumberg       StringRef USR =
699529a0570SDaniel Grumberg           API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM);
700529a0570SDaniel Grumberg 
701529a0570SDaniel Grumberg       API.addMacroDefinition(
702529a0570SDaniel Grumberg           Name, USR, Loc,
703529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
704529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getSubHeadingForMacro(Name));
705529a0570SDaniel Grumberg     }
706529a0570SDaniel Grumberg 
707529a0570SDaniel Grumberg     PendingMacros.clear();
708529a0570SDaniel Grumberg   }
709529a0570SDaniel Grumberg 
710529a0570SDaniel Grumberg private:
711529a0570SDaniel Grumberg   struct PendingMacro {
712529a0570SDaniel Grumberg     Token MacroNameToken;
713529a0570SDaniel Grumberg     const MacroDirective *MD;
714529a0570SDaniel Grumberg 
715529a0570SDaniel Grumberg     PendingMacro(const Token &MacroNameToken, const MacroDirective *MD)
716529a0570SDaniel Grumberg         : MacroNameToken(MacroNameToken), MD(MD) {}
717529a0570SDaniel Grumberg   };
718529a0570SDaniel Grumberg 
719529a0570SDaniel Grumberg   const SourceManager &SM;
720*aebe5fc6SDaniel Grumberg   LocationFileChecker &LCF;
721529a0570SDaniel Grumberg   APISet &API;
722529a0570SDaniel Grumberg   llvm::SmallVector<PendingMacro> PendingMacros;
723529a0570SDaniel Grumberg };
724529a0570SDaniel Grumberg 
72589f6b26fSZixu Wang } // namespace
72689f6b26fSZixu Wang 
72789f6b26fSZixu Wang std::unique_ptr<ASTConsumer>
72889f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
729a9909d23SDaniel Grumberg   OS = CreateOutputFile(CI, InFile);
73089f6b26fSZixu Wang   if (!OS)
73189f6b26fSZixu Wang     return nullptr;
732a9909d23SDaniel Grumberg 
733a9909d23SDaniel Grumberg   ProductName = CI.getFrontendOpts().ProductName;
734a9909d23SDaniel Grumberg 
735a9909d23SDaniel Grumberg   // Now that we have enough information about the language options and the
736a9909d23SDaniel Grumberg   // target triple, let's create the APISet before anyone uses it.
737a9909d23SDaniel Grumberg   API = std::make_unique<APISet>(
738a9909d23SDaniel Grumberg       CI.getTarget().getTriple(),
739a9909d23SDaniel Grumberg       CI.getFrontendOpts().Inputs.back().getKind().getLanguage());
740a9909d23SDaniel Grumberg 
741*aebe5fc6SDaniel Grumberg   auto LCF = std::make_unique<LocationFileChecker>(CI.getSourceManager(),
742*aebe5fc6SDaniel Grumberg                                                    KnownInputFiles);
743*aebe5fc6SDaniel Grumberg 
744529a0570SDaniel Grumberg   // Register preprocessor callbacks that will add macro definitions to API.
745529a0570SDaniel Grumberg   CI.getPreprocessor().addPPCallbacks(
746*aebe5fc6SDaniel Grumberg       std::make_unique<MacroCallback>(CI.getSourceManager(), *LCF, *API));
747529a0570SDaniel Grumberg 
748*aebe5fc6SDaniel Grumberg   return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
749*aebe5fc6SDaniel Grumberg                                               std::move(LCF), *API);
75089f6b26fSZixu Wang }
75189f6b26fSZixu Wang 
752f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
753f833aab0SDaniel Grumberg   auto &Inputs = CI.getFrontendOpts().Inputs;
754f833aab0SDaniel Grumberg   if (Inputs.empty())
755f833aab0SDaniel Grumberg     return true;
756f833aab0SDaniel Grumberg 
757f833aab0SDaniel Grumberg   auto Kind = Inputs[0].getKind();
758f833aab0SDaniel Grumberg 
759f833aab0SDaniel Grumberg   // Convert the header file inputs into a single input buffer.
760f833aab0SDaniel Grumberg   SmallString<256> HeaderContents;
761f833aab0SDaniel Grumberg   for (const FrontendInputFile &FIF : Inputs) {
762f833aab0SDaniel Grumberg     if (Kind.isObjectiveC())
763f833aab0SDaniel Grumberg       HeaderContents += "#import";
764f833aab0SDaniel Grumberg     else
765f833aab0SDaniel Grumberg       HeaderContents += "#include";
766f833aab0SDaniel Grumberg     HeaderContents += " \"";
767f833aab0SDaniel Grumberg     HeaderContents += FIF.getFile();
768f833aab0SDaniel Grumberg     HeaderContents += "\"\n";
769*aebe5fc6SDaniel Grumberg 
770*aebe5fc6SDaniel Grumberg     KnownInputFiles.emplace_back(FIF.getFile());
771f833aab0SDaniel Grumberg   }
772f833aab0SDaniel Grumberg 
773985eaa1aSDaniel Grumberg   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
774f833aab0SDaniel Grumberg                                                 getInputBufferName());
775f833aab0SDaniel Grumberg 
776f833aab0SDaniel Grumberg   // Set that buffer up as our "real" input in the CompilerInstance.
777f833aab0SDaniel Grumberg   Inputs.clear();
778f833aab0SDaniel Grumberg   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
779f833aab0SDaniel Grumberg 
780f833aab0SDaniel Grumberg   return true;
781f833aab0SDaniel Grumberg }
782f833aab0SDaniel Grumberg 
783a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() {
784a9909d23SDaniel Grumberg   if (!OS)
785a9909d23SDaniel Grumberg     return;
786a9909d23SDaniel Grumberg 
787a9909d23SDaniel Grumberg   // Setup a SymbolGraphSerializer to write out collected API information in
788a9909d23SDaniel Grumberg   // the Symbol Graph format.
789a9909d23SDaniel Grumberg   // FIXME: Make the kind of APISerializer configurable.
790a9909d23SDaniel Grumberg   SymbolGraphSerializer SGSerializer(*API, ProductName);
791a9909d23SDaniel Grumberg   SGSerializer.serialize(*OS);
792a9909d23SDaniel Grumberg   OS->flush();
793a9909d23SDaniel Grumberg }
794a9909d23SDaniel Grumberg 
79589f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream>
79689f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
79789f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS =
79889f6b26fSZixu Wang       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
79989f6b26fSZixu Wang                                  /*RemoveFileOnSignal=*/false);
80089f6b26fSZixu Wang   if (!OS)
80189f6b26fSZixu Wang     return nullptr;
80289f6b26fSZixu Wang   return OS;
80389f6b26fSZixu Wang }
804