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"
23aebe5fc6SDaniel Grumberg #include "clang/Basic/SourceLocation.h"
24aebe5fc6SDaniel 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"
36aebe5fc6SDaniel Grumberg #include "clang/Lex/Preprocessor.h"
37529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h"
38aebe5fc6SDaniel 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"
43aebe5fc6SDaniel Grumberg #include <memory>
44aebe5fc6SDaniel 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 
58aebe5fc6SDaniel Grumberg struct LocationFileChecker {
59aebe5fc6SDaniel Grumberg   bool isLocationInKnownFile(SourceLocation Loc) {
60aebe5fc6SDaniel Grumberg     // If the loc refers to a macro expansion we need to first get the file
61aebe5fc6SDaniel Grumberg     // location of the expansion.
62aebe5fc6SDaniel Grumberg     auto FileLoc = SM.getFileLoc(Loc);
63aebe5fc6SDaniel Grumberg     FileID FID = SM.getFileID(FileLoc);
64aebe5fc6SDaniel Grumberg     if (FID.isInvalid())
65aebe5fc6SDaniel Grumberg       return false;
66aebe5fc6SDaniel Grumberg 
67aebe5fc6SDaniel Grumberg     const auto *File = SM.getFileEntryForID(FID);
68aebe5fc6SDaniel Grumberg     if (!File)
69aebe5fc6SDaniel Grumberg       return false;
70aebe5fc6SDaniel Grumberg 
71aebe5fc6SDaniel Grumberg     if (KnownFileEntries.count(File))
72aebe5fc6SDaniel Grumberg       return true;
73aebe5fc6SDaniel Grumberg 
74aebe5fc6SDaniel Grumberg     return false;
75aebe5fc6SDaniel Grumberg   }
76aebe5fc6SDaniel Grumberg 
77*2966f0faSZixu Wang   LocationFileChecker(const SourceManager &SM,
78*2966f0faSZixu Wang                       const std::vector<std::string> &KnownFiles)
79*2966f0faSZixu Wang       : SM(SM) {
80*2966f0faSZixu Wang     for (const auto &KnownFilePath : KnownFiles)
81*2966f0faSZixu Wang       if (auto FileEntry = SM.getFileManager().getFile(KnownFilePath))
82aebe5fc6SDaniel Grumberg         KnownFileEntries.insert(*FileEntry);
83aebe5fc6SDaniel Grumberg   }
84aebe5fc6SDaniel Grumberg 
85aebe5fc6SDaniel Grumberg private:
86*2966f0faSZixu Wang   const SourceManager &SM;
87aebe5fc6SDaniel Grumberg   llvm::DenseSet<const FileEntry *> KnownFileEntries;
88aebe5fc6SDaniel Grumberg };
89aebe5fc6SDaniel 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:
94aebe5fc6SDaniel Grumberg   ExtractAPIVisitor(ASTContext &Context, LocationFileChecker &LCF, APISet &API)
95aebe5fc6SDaniel 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 
117aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
118aebe5fc6SDaniel Grumberg       return true;
119aebe5fc6SDaniel 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 
177aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
178aebe5fc6SDaniel Grumberg       return true;
179aebe5fc6SDaniel 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.
201236b6a0eSDaniel Grumberg     API.addGlobalFunction(Name, USR, Loc, Availability, Linkage, Comment,
202236b6a0eSDaniel Grumberg                           Declaration, 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 
214aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
215aebe5fc6SDaniel Grumberg       return true;
216aebe5fc6SDaniel Grumberg 
21771b4c226SZixu Wang     // Collect symbol information.
2187443a504SDaniel Grumberg     std::string NameString = Decl->getQualifiedNameAsString();
2197443a504SDaniel Grumberg     StringRef Name(NameString);
2209fc45ca0SDaniel Grumberg     if (Name.empty())
2219fc45ca0SDaniel Grumberg       Name = getTypedefName(Decl);
2227443a504SDaniel Grumberg 
22371b4c226SZixu Wang     StringRef USR = API.recordUSR(Decl);
22471b4c226SZixu Wang     PresumedLoc Loc =
22571b4c226SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
22671b4c226SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
22771b4c226SZixu Wang     DocComment Comment;
22871b4c226SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
22971b4c226SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
23071b4c226SZixu Wang                                               Context.getDiagnostics());
23171b4c226SZixu Wang 
23271b4c226SZixu Wang     // Build declaration fragments and sub-heading for the enum.
23371b4c226SZixu Wang     DeclarationFragments Declaration =
23471b4c226SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
23571b4c226SZixu Wang     DeclarationFragments SubHeading =
23671b4c226SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
23771b4c226SZixu Wang 
2387443a504SDaniel Grumberg     EnumRecord *EnumRecord =
2397443a504SDaniel Grumberg         API.addEnum(API.copyString(Name), USR, Loc, Availability, Comment,
24071b4c226SZixu Wang                     Declaration, SubHeading);
24171b4c226SZixu Wang 
24271b4c226SZixu Wang     // Now collect information about the enumerators in this enum.
24371b4c226SZixu Wang     recordEnumConstants(EnumRecord, Decl->enumerators());
24471b4c226SZixu Wang 
24571b4c226SZixu Wang     return true;
24671b4c226SZixu Wang   }
24771b4c226SZixu Wang 
2485bb5704cSZixu Wang   bool VisitRecordDecl(const RecordDecl *Decl) {
2495bb5704cSZixu Wang     if (!Decl->isCompleteDefinition())
2505bb5704cSZixu Wang       return true;
2515bb5704cSZixu Wang 
2525bb5704cSZixu Wang     // Skip C++ structs/classes/unions
2535bb5704cSZixu Wang     // TODO: support C++ records
2545bb5704cSZixu Wang     if (isa<CXXRecordDecl>(Decl))
2555bb5704cSZixu Wang       return true;
2565bb5704cSZixu Wang 
257aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
258aebe5fc6SDaniel Grumberg       return true;
259aebe5fc6SDaniel Grumberg 
2605bb5704cSZixu Wang     // Collect symbol information.
2615bb5704cSZixu Wang     StringRef Name = Decl->getName();
2629fc45ca0SDaniel Grumberg     if (Name.empty())
2639fc45ca0SDaniel Grumberg       Name = getTypedefName(Decl);
2645bb5704cSZixu Wang     StringRef USR = API.recordUSR(Decl);
2655bb5704cSZixu Wang     PresumedLoc Loc =
2665bb5704cSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2675bb5704cSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2685bb5704cSZixu Wang     DocComment Comment;
2695bb5704cSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2705bb5704cSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2715bb5704cSZixu Wang                                               Context.getDiagnostics());
2725bb5704cSZixu Wang 
2735bb5704cSZixu Wang     // Build declaration fragments and sub-heading for the struct.
2745bb5704cSZixu Wang     DeclarationFragments Declaration =
2755bb5704cSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
2765bb5704cSZixu Wang     DeclarationFragments SubHeading =
2775bb5704cSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2785bb5704cSZixu Wang 
2795bb5704cSZixu Wang     StructRecord *StructRecord = API.addStruct(
2805bb5704cSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
2815bb5704cSZixu Wang 
2825bb5704cSZixu Wang     // Now collect information about the fields in this struct.
2835bb5704cSZixu Wang     recordStructFields(StructRecord, Decl->fields());
2845bb5704cSZixu Wang 
2855bb5704cSZixu Wang     return true;
2865bb5704cSZixu Wang   }
2875bb5704cSZixu Wang 
2889b36e126SZixu Wang   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
2899b36e126SZixu Wang     // Skip forward declaration for classes (@class)
2909b36e126SZixu Wang     if (!Decl->isThisDeclarationADefinition())
2919b36e126SZixu Wang       return true;
2929b36e126SZixu Wang 
293aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
294aebe5fc6SDaniel Grumberg       return true;
295aebe5fc6SDaniel Grumberg 
2969b36e126SZixu Wang     // Collect symbol information.
2979b36e126SZixu Wang     StringRef Name = Decl->getName();
2989b36e126SZixu Wang     StringRef USR = API.recordUSR(Decl);
2999b36e126SZixu Wang     PresumedLoc Loc =
3009b36e126SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
3019b36e126SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
3029b36e126SZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
3039b36e126SZixu Wang     DocComment Comment;
3049b36e126SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
3059b36e126SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3069b36e126SZixu Wang                                               Context.getDiagnostics());
3079b36e126SZixu Wang 
3089b36e126SZixu Wang     // Build declaration fragments and sub-heading for the interface.
3099b36e126SZixu Wang     DeclarationFragments Declaration =
3109b36e126SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
3119b36e126SZixu Wang     DeclarationFragments SubHeading =
3129b36e126SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
3139b36e126SZixu Wang 
3149b36e126SZixu Wang     // Collect super class information.
3159b36e126SZixu Wang     SymbolReference SuperClass;
3169b36e126SZixu Wang     if (const auto *SuperClassDecl = Decl->getSuperClass()) {
3179b36e126SZixu Wang       SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
3189b36e126SZixu Wang       SuperClass.USR = API.recordUSR(SuperClassDecl);
3199b36e126SZixu Wang     }
3209b36e126SZixu Wang 
3219b36e126SZixu Wang     ObjCInterfaceRecord *ObjCInterfaceRecord =
3229b36e126SZixu Wang         API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
3239b36e126SZixu Wang                              Declaration, SubHeading, SuperClass);
3249b36e126SZixu Wang 
3259b36e126SZixu Wang     // Record all methods (selectors). This doesn't include automatically
3269b36e126SZixu Wang     // synthesized property methods.
3279b36e126SZixu Wang     recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
3289b36e126SZixu Wang     recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
3299b36e126SZixu Wang     recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
3309b36e126SZixu Wang     recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
3319b36e126SZixu Wang 
3329b36e126SZixu Wang     return true;
3339b36e126SZixu Wang   }
3349b36e126SZixu Wang 
335d1d34bafSZixu Wang   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
336d1d34bafSZixu Wang     // Skip forward declaration for protocols (@protocol).
337d1d34bafSZixu Wang     if (!Decl->isThisDeclarationADefinition())
338d1d34bafSZixu Wang       return true;
339d1d34bafSZixu Wang 
340aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
341aebe5fc6SDaniel Grumberg       return true;
342aebe5fc6SDaniel Grumberg 
343d1d34bafSZixu Wang     // Collect symbol information.
344d1d34bafSZixu Wang     StringRef Name = Decl->getName();
345d1d34bafSZixu Wang     StringRef USR = API.recordUSR(Decl);
346d1d34bafSZixu Wang     PresumedLoc Loc =
347d1d34bafSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
348d1d34bafSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
349d1d34bafSZixu Wang     DocComment Comment;
350d1d34bafSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
351d1d34bafSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
352d1d34bafSZixu Wang                                               Context.getDiagnostics());
353d1d34bafSZixu Wang 
354d1d34bafSZixu Wang     // Build declaration fragments and sub-heading for the protocol.
355d1d34bafSZixu Wang     DeclarationFragments Declaration =
356d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
357d1d34bafSZixu Wang     DeclarationFragments SubHeading =
358d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
359d1d34bafSZixu Wang 
360d1d34bafSZixu Wang     ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
361d1d34bafSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
362d1d34bafSZixu Wang 
363d1d34bafSZixu Wang     recordObjCMethods(ObjCProtocolRecord, Decl->methods());
364d1d34bafSZixu Wang     recordObjCProperties(ObjCProtocolRecord, Decl->properties());
365d1d34bafSZixu Wang     recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
366d1d34bafSZixu Wang 
367d1d34bafSZixu Wang     return true;
368d1d34bafSZixu Wang   }
369d1d34bafSZixu Wang 
3709fc45ca0SDaniel Grumberg   bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
3719fc45ca0SDaniel Grumberg     // Skip ObjC Type Parameter for now.
3729fc45ca0SDaniel Grumberg     if (isa<ObjCTypeParamDecl>(Decl))
3739fc45ca0SDaniel Grumberg       return true;
3749fc45ca0SDaniel Grumberg 
3759fc45ca0SDaniel Grumberg     if (!Decl->isDefinedOutsideFunctionOrMethod())
3769fc45ca0SDaniel Grumberg       return true;
3779fc45ca0SDaniel Grumberg 
378aebe5fc6SDaniel Grumberg     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
379aebe5fc6SDaniel Grumberg       return true;
380aebe5fc6SDaniel Grumberg 
3819fc45ca0SDaniel Grumberg     PresumedLoc Loc =
3829fc45ca0SDaniel Grumberg         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
3839fc45ca0SDaniel Grumberg     StringRef Name = Decl->getName();
3849fc45ca0SDaniel Grumberg     AvailabilityInfo Availability = getAvailability(Decl);
3859fc45ca0SDaniel Grumberg     StringRef USR = API.recordUSR(Decl);
3869fc45ca0SDaniel Grumberg     DocComment Comment;
3879fc45ca0SDaniel Grumberg     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
3889fc45ca0SDaniel Grumberg       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3899fc45ca0SDaniel Grumberg                                               Context.getDiagnostics());
3909fc45ca0SDaniel Grumberg 
3919fc45ca0SDaniel Grumberg     QualType Type = Decl->getUnderlyingType();
3929fc45ca0SDaniel Grumberg     SymbolReference SymRef =
3939fc45ca0SDaniel Grumberg         TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
3949fc45ca0SDaniel Grumberg                                                                          API);
3959fc45ca0SDaniel Grumberg 
3969fc45ca0SDaniel Grumberg     API.addTypedef(Name, USR, Loc, Availability, Comment,
3979fc45ca0SDaniel Grumberg                    DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
3989fc45ca0SDaniel Grumberg                    DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
3999fc45ca0SDaniel Grumberg 
4009fc45ca0SDaniel Grumberg     return true;
4019fc45ca0SDaniel Grumberg   }
4029fc45ca0SDaniel Grumberg 
403178aad9bSZixu Wang   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
404178aad9bSZixu Wang     // Collect symbol information.
405178aad9bSZixu Wang     StringRef Name = Decl->getName();
406178aad9bSZixu Wang     StringRef USR = API.recordUSR(Decl);
407178aad9bSZixu Wang     PresumedLoc Loc =
408178aad9bSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
409178aad9bSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
410178aad9bSZixu Wang     DocComment Comment;
411178aad9bSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
412178aad9bSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
413178aad9bSZixu Wang                                               Context.getDiagnostics());
414178aad9bSZixu Wang     // Build declaration fragments and sub-heading for the category.
415178aad9bSZixu Wang     DeclarationFragments Declaration =
416178aad9bSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
417178aad9bSZixu Wang     DeclarationFragments SubHeading =
418178aad9bSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
419178aad9bSZixu Wang 
420178aad9bSZixu Wang     const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
421178aad9bSZixu Wang     SymbolReference Interface(InterfaceDecl->getName(),
422178aad9bSZixu Wang                               API.recordUSR(InterfaceDecl));
423178aad9bSZixu Wang 
424178aad9bSZixu Wang     ObjCCategoryRecord *ObjCCategoryRecord =
425178aad9bSZixu Wang         API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration,
426178aad9bSZixu Wang                             SubHeading, Interface);
427178aad9bSZixu Wang 
428178aad9bSZixu Wang     recordObjCMethods(ObjCCategoryRecord, Decl->methods());
429178aad9bSZixu Wang     recordObjCProperties(ObjCCategoryRecord, Decl->properties());
430178aad9bSZixu Wang     recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
431178aad9bSZixu Wang     recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
432178aad9bSZixu Wang 
433178aad9bSZixu Wang     return true;
434178aad9bSZixu Wang   }
435178aad9bSZixu Wang 
43689f6b26fSZixu Wang private:
43789f6b26fSZixu Wang   /// Get availability information of the declaration \p D.
43889f6b26fSZixu Wang   AvailabilityInfo getAvailability(const Decl *D) const {
43989f6b26fSZixu Wang     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
44089f6b26fSZixu Wang 
44189f6b26fSZixu Wang     AvailabilityInfo Availability;
44289f6b26fSZixu Wang     // Collect availability attributes from all redeclarations.
44389f6b26fSZixu Wang     for (const auto *RD : D->redecls()) {
44489f6b26fSZixu Wang       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
44589f6b26fSZixu Wang         if (A->getPlatform()->getName() != PlatformName)
44689f6b26fSZixu Wang           continue;
44789f6b26fSZixu Wang         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
44889f6b26fSZixu Wang                                         A->getObsoleted(), A->getUnavailable(),
44989f6b26fSZixu Wang                                         /* UnconditionallyDeprecated */ false,
45089f6b26fSZixu Wang                                         /* UnconditionallyUnavailable */ false);
45189f6b26fSZixu Wang         break;
45289f6b26fSZixu Wang       }
45389f6b26fSZixu Wang 
45489f6b26fSZixu Wang       if (const auto *A = RD->getAttr<UnavailableAttr>())
45589f6b26fSZixu Wang         if (!A->isImplicit()) {
45689f6b26fSZixu Wang           Availability.Unavailable = true;
45789f6b26fSZixu Wang           Availability.UnconditionallyUnavailable = true;
45889f6b26fSZixu Wang         }
45989f6b26fSZixu Wang 
46089f6b26fSZixu Wang       if (const auto *A = RD->getAttr<DeprecatedAttr>())
46189f6b26fSZixu Wang         if (!A->isImplicit())
46289f6b26fSZixu Wang           Availability.UnconditionallyDeprecated = true;
46389f6b26fSZixu Wang     }
46489f6b26fSZixu Wang 
46589f6b26fSZixu Wang     return Availability;
46689f6b26fSZixu Wang   }
46789f6b26fSZixu Wang 
46871b4c226SZixu Wang   /// Collect API information for the enum constants and associate with the
46971b4c226SZixu Wang   /// parent enum.
47071b4c226SZixu Wang   void recordEnumConstants(EnumRecord *EnumRecord,
47171b4c226SZixu Wang                            const EnumDecl::enumerator_range Constants) {
47271b4c226SZixu Wang     for (const auto *Constant : Constants) {
47371b4c226SZixu Wang       // Collect symbol information.
47471b4c226SZixu Wang       StringRef Name = Constant->getName();
47571b4c226SZixu Wang       StringRef USR = API.recordUSR(Constant);
47671b4c226SZixu Wang       PresumedLoc Loc =
47771b4c226SZixu Wang           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
47871b4c226SZixu Wang       AvailabilityInfo Availability = getAvailability(Constant);
47971b4c226SZixu Wang       DocComment Comment;
48071b4c226SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
48171b4c226SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
48271b4c226SZixu Wang                                                 Context.getDiagnostics());
48371b4c226SZixu Wang 
48471b4c226SZixu Wang       // Build declaration fragments and sub-heading for the enum constant.
48571b4c226SZixu Wang       DeclarationFragments Declaration =
48671b4c226SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
48771b4c226SZixu Wang       DeclarationFragments SubHeading =
48871b4c226SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Constant);
48971b4c226SZixu Wang 
49071b4c226SZixu Wang       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
49171b4c226SZixu Wang                           Declaration, SubHeading);
49271b4c226SZixu Wang     }
49371b4c226SZixu Wang   }
49471b4c226SZixu Wang 
4955bb5704cSZixu Wang   /// Collect API information for the struct fields and associate with the
4965bb5704cSZixu Wang   /// parent struct.
4975bb5704cSZixu Wang   void recordStructFields(StructRecord *StructRecord,
4985bb5704cSZixu Wang                           const RecordDecl::field_range Fields) {
4995bb5704cSZixu Wang     for (const auto *Field : Fields) {
5005bb5704cSZixu Wang       // Collect symbol information.
5015bb5704cSZixu Wang       StringRef Name = Field->getName();
5025bb5704cSZixu Wang       StringRef USR = API.recordUSR(Field);
5035bb5704cSZixu Wang       PresumedLoc Loc =
5045bb5704cSZixu Wang           Context.getSourceManager().getPresumedLoc(Field->getLocation());
5055bb5704cSZixu Wang       AvailabilityInfo Availability = getAvailability(Field);
5065bb5704cSZixu Wang       DocComment Comment;
5075bb5704cSZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
5085bb5704cSZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5095bb5704cSZixu Wang                                                 Context.getDiagnostics());
5105bb5704cSZixu Wang 
5115bb5704cSZixu Wang       // Build declaration fragments and sub-heading for the struct field.
5125bb5704cSZixu Wang       DeclarationFragments Declaration =
5135bb5704cSZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Field);
5145bb5704cSZixu Wang       DeclarationFragments SubHeading =
5155bb5704cSZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Field);
5165bb5704cSZixu Wang 
5175bb5704cSZixu Wang       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
5185bb5704cSZixu Wang                          Declaration, SubHeading);
5195bb5704cSZixu Wang     }
5205bb5704cSZixu Wang   }
5215bb5704cSZixu Wang 
5229b36e126SZixu Wang   /// Collect API information for the Objective-C methods and associate with the
5239b36e126SZixu Wang   /// parent container.
5249b36e126SZixu Wang   void recordObjCMethods(ObjCContainerRecord *Container,
5259b36e126SZixu Wang                          const ObjCContainerDecl::method_range Methods) {
5269b36e126SZixu Wang     for (const auto *Method : Methods) {
5279b36e126SZixu Wang       // Don't record selectors for properties.
5289b36e126SZixu Wang       if (Method->isPropertyAccessor())
5299b36e126SZixu Wang         continue;
5309b36e126SZixu Wang 
5319b36e126SZixu Wang       StringRef Name = API.copyString(Method->getSelector().getAsString());
5329b36e126SZixu Wang       StringRef USR = API.recordUSR(Method);
5339b36e126SZixu Wang       PresumedLoc Loc =
5349b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Method->getLocation());
5359b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Method);
5369b36e126SZixu Wang       DocComment Comment;
5379b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
5389b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5399b36e126SZixu Wang                                                 Context.getDiagnostics());
5409b36e126SZixu Wang 
5419b36e126SZixu Wang       // Build declaration fragments, sub-heading, and signature for the method.
5429b36e126SZixu Wang       DeclarationFragments Declaration =
5439b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
5449b36e126SZixu Wang       DeclarationFragments SubHeading =
5459b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Method);
5469b36e126SZixu Wang       FunctionSignature Signature =
5479b36e126SZixu Wang           DeclarationFragmentsBuilder::getFunctionSignature(Method);
5489b36e126SZixu Wang 
5499b36e126SZixu Wang       API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
5509b36e126SZixu Wang                         Declaration, SubHeading, Signature,
5519b36e126SZixu Wang                         Method->isInstanceMethod());
5529b36e126SZixu Wang     }
5539b36e126SZixu Wang   }
5549b36e126SZixu Wang 
5559b36e126SZixu Wang   void recordObjCProperties(ObjCContainerRecord *Container,
5569b36e126SZixu Wang                             const ObjCContainerDecl::prop_range Properties) {
5579b36e126SZixu Wang     for (const auto *Property : Properties) {
5589b36e126SZixu Wang       StringRef Name = Property->getName();
5599b36e126SZixu Wang       StringRef USR = API.recordUSR(Property);
5609b36e126SZixu Wang       PresumedLoc Loc =
5619b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Property->getLocation());
5629b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Property);
5639b36e126SZixu Wang       DocComment Comment;
5649b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
5659b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
5669b36e126SZixu Wang                                                 Context.getDiagnostics());
5679b36e126SZixu Wang 
5689b36e126SZixu Wang       // Build declaration fragments and sub-heading for the property.
5699b36e126SZixu Wang       DeclarationFragments Declaration =
5709b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
5719b36e126SZixu Wang       DeclarationFragments SubHeading =
5729b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Property);
5739b36e126SZixu Wang 
5749b36e126SZixu Wang       StringRef GetterName =
5759b36e126SZixu Wang           API.copyString(Property->getGetterName().getAsString());
5769b36e126SZixu Wang       StringRef SetterName =
5779b36e126SZixu Wang           API.copyString(Property->getSetterName().getAsString());
5789b36e126SZixu Wang 
5799b36e126SZixu Wang       // Get the attributes for property.
5809b36e126SZixu Wang       unsigned Attributes = ObjCPropertyRecord::NoAttr;
5819b36e126SZixu Wang       if (Property->getPropertyAttributes() &
5829b36e126SZixu Wang           ObjCPropertyAttribute::kind_readonly)
5839b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::ReadOnly;
5849b36e126SZixu Wang       if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
5859b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::Class;
5869b36e126SZixu Wang 
5879b36e126SZixu Wang       API.addObjCProperty(
5889b36e126SZixu Wang           Container, Name, USR, Loc, Availability, Comment, Declaration,
5899b36e126SZixu Wang           SubHeading,
5909b36e126SZixu Wang           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
5919b36e126SZixu Wang           GetterName, SetterName, Property->isOptional());
5929b36e126SZixu Wang     }
5939b36e126SZixu Wang   }
5949b36e126SZixu Wang 
5959b36e126SZixu Wang   void recordObjCInstanceVariables(
5969b36e126SZixu Wang       ObjCContainerRecord *Container,
5979b36e126SZixu Wang       const llvm::iterator_range<
5989b36e126SZixu Wang           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
5999b36e126SZixu Wang           Ivars) {
6009b36e126SZixu Wang     for (const auto *Ivar : Ivars) {
6019b36e126SZixu Wang       StringRef Name = Ivar->getName();
6029b36e126SZixu Wang       StringRef USR = API.recordUSR(Ivar);
6039b36e126SZixu Wang       PresumedLoc Loc =
6049b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
6059b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Ivar);
6069b36e126SZixu Wang       DocComment Comment;
6079b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
6089b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
6099b36e126SZixu Wang                                                 Context.getDiagnostics());
6109b36e126SZixu Wang 
6119b36e126SZixu Wang       // Build declaration fragments and sub-heading for the instance variable.
6129b36e126SZixu Wang       DeclarationFragments Declaration =
6139b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
6149b36e126SZixu Wang       DeclarationFragments SubHeading =
6159b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Ivar);
6169b36e126SZixu Wang 
6179b36e126SZixu Wang       ObjCInstanceVariableRecord::AccessControl Access =
6189b36e126SZixu Wang           Ivar->getCanonicalAccessControl();
6199b36e126SZixu Wang 
6209b36e126SZixu Wang       API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
6219b36e126SZixu Wang                                   Comment, Declaration, SubHeading, Access);
6229b36e126SZixu Wang     }
6239b36e126SZixu Wang   }
6249b36e126SZixu Wang 
6259b36e126SZixu Wang   void recordObjCProtocols(ObjCContainerRecord *Container,
6269b36e126SZixu Wang                            ObjCInterfaceDecl::protocol_range Protocols) {
6279b36e126SZixu Wang     for (const auto *Protocol : Protocols)
6289b36e126SZixu Wang       Container->Protocols.emplace_back(Protocol->getName(),
6299b36e126SZixu Wang                                         API.recordUSR(Protocol));
6309b36e126SZixu Wang   }
6319b36e126SZixu Wang 
63289f6b26fSZixu Wang   ASTContext &Context;
633a9909d23SDaniel Grumberg   APISet &API;
634aebe5fc6SDaniel Grumberg   LocationFileChecker &LCF;
63589f6b26fSZixu Wang };
63689f6b26fSZixu Wang 
63789f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer {
63889f6b26fSZixu Wang public:
639aebe5fc6SDaniel Grumberg   ExtractAPIConsumer(ASTContext &Context,
640aebe5fc6SDaniel Grumberg                      std::unique_ptr<LocationFileChecker> LCF, APISet &API)
641aebe5fc6SDaniel Grumberg       : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {}
64289f6b26fSZixu Wang 
64389f6b26fSZixu Wang   void HandleTranslationUnit(ASTContext &Context) override {
64489f6b26fSZixu Wang     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
64589f6b26fSZixu Wang     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
64689f6b26fSZixu Wang   }
64789f6b26fSZixu Wang 
64889f6b26fSZixu Wang private:
64989f6b26fSZixu Wang   ExtractAPIVisitor Visitor;
650aebe5fc6SDaniel Grumberg   std::unique_ptr<LocationFileChecker> LCF;
65189f6b26fSZixu Wang };
65289f6b26fSZixu Wang 
653529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks {
654529a0570SDaniel Grumberg public:
65510155922SDaniel Grumberg   MacroCallback(const SourceManager &SM, LocationFileChecker &LCF, APISet &API,
65610155922SDaniel Grumberg                 Preprocessor &PP)
65710155922SDaniel Grumberg       : SM(SM), LCF(LCF), API(API), PP(PP) {}
658529a0570SDaniel Grumberg 
659529a0570SDaniel Grumberg   void MacroDefined(const Token &MacroNameToken,
660529a0570SDaniel Grumberg                     const MacroDirective *MD) override {
661529a0570SDaniel Grumberg     auto *MacroInfo = MD->getMacroInfo();
662529a0570SDaniel Grumberg 
663529a0570SDaniel Grumberg     if (MacroInfo->isBuiltinMacro())
664529a0570SDaniel Grumberg       return;
665529a0570SDaniel Grumberg 
666529a0570SDaniel Grumberg     auto SourceLoc = MacroNameToken.getLocation();
667529a0570SDaniel Grumberg     if (SM.isWrittenInBuiltinFile(SourceLoc) ||
668529a0570SDaniel Grumberg         SM.isWrittenInCommandLineFile(SourceLoc))
669529a0570SDaniel Grumberg       return;
670529a0570SDaniel Grumberg 
671529a0570SDaniel Grumberg     PendingMacros.emplace_back(MacroNameToken, MD);
672529a0570SDaniel Grumberg   }
673529a0570SDaniel Grumberg 
674529a0570SDaniel Grumberg   // If a macro gets undefined at some point during preprocessing of the inputs
675529a0570SDaniel Grumberg   // it means that it isn't an exposed API and we should therefore not add a
676529a0570SDaniel Grumberg   // macro definition for it.
677529a0570SDaniel Grumberg   void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD,
678529a0570SDaniel Grumberg                       const MacroDirective *Undef) override {
6798b63622bSDaniel Grumberg     // If this macro wasn't previously defined we don't need to do anything
6808b63622bSDaniel Grumberg     // here.
6818b63622bSDaniel Grumberg     if (!Undef)
6828b63622bSDaniel Grumberg       return;
6838b63622bSDaniel Grumberg 
68410155922SDaniel Grumberg     llvm::erase_if(PendingMacros, [&MD, this](const PendingMacro &PM) {
68510155922SDaniel Grumberg       return MD.getMacroInfo()->isIdenticalTo(*PM.MD->getMacroInfo(), PP,
68610155922SDaniel Grumberg                                               /*Syntactically*/ false);
687529a0570SDaniel Grumberg     });
688529a0570SDaniel Grumberg   }
689529a0570SDaniel Grumberg 
690529a0570SDaniel Grumberg   void EndOfMainFile() override {
691529a0570SDaniel Grumberg     for (auto &PM : PendingMacros) {
692529a0570SDaniel Grumberg       // `isUsedForHeaderGuard` is only set when the preprocessor leaves the
693529a0570SDaniel Grumberg       // file so check for it here.
694529a0570SDaniel Grumberg       if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
695529a0570SDaniel Grumberg         continue;
696529a0570SDaniel Grumberg 
697aebe5fc6SDaniel Grumberg       if (!LCF.isLocationInKnownFile(PM.MacroNameToken.getLocation()))
698aebe5fc6SDaniel Grumberg         continue;
699aebe5fc6SDaniel Grumberg 
700529a0570SDaniel Grumberg       StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
701529a0570SDaniel Grumberg       PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation());
702529a0570SDaniel Grumberg       StringRef USR =
703529a0570SDaniel Grumberg           API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM);
704529a0570SDaniel Grumberg 
705529a0570SDaniel Grumberg       API.addMacroDefinition(
706529a0570SDaniel Grumberg           Name, USR, Loc,
707529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
708529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getSubHeadingForMacro(Name));
709529a0570SDaniel Grumberg     }
710529a0570SDaniel Grumberg 
711529a0570SDaniel Grumberg     PendingMacros.clear();
712529a0570SDaniel Grumberg   }
713529a0570SDaniel Grumberg 
714529a0570SDaniel Grumberg private:
715529a0570SDaniel Grumberg   struct PendingMacro {
716529a0570SDaniel Grumberg     Token MacroNameToken;
717529a0570SDaniel Grumberg     const MacroDirective *MD;
718529a0570SDaniel Grumberg 
719529a0570SDaniel Grumberg     PendingMacro(const Token &MacroNameToken, const MacroDirective *MD)
720529a0570SDaniel Grumberg         : MacroNameToken(MacroNameToken), MD(MD) {}
721529a0570SDaniel Grumberg   };
722529a0570SDaniel Grumberg 
723529a0570SDaniel Grumberg   const SourceManager &SM;
724aebe5fc6SDaniel Grumberg   LocationFileChecker &LCF;
725529a0570SDaniel Grumberg   APISet &API;
72610155922SDaniel Grumberg   Preprocessor &PP;
727529a0570SDaniel Grumberg   llvm::SmallVector<PendingMacro> PendingMacros;
728529a0570SDaniel Grumberg };
729529a0570SDaniel Grumberg 
73089f6b26fSZixu Wang } // namespace
73189f6b26fSZixu Wang 
73289f6b26fSZixu Wang std::unique_ptr<ASTConsumer>
73389f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
734a9909d23SDaniel Grumberg   OS = CreateOutputFile(CI, InFile);
73589f6b26fSZixu Wang   if (!OS)
73689f6b26fSZixu Wang     return nullptr;
737a9909d23SDaniel Grumberg 
738a9909d23SDaniel Grumberg   ProductName = CI.getFrontendOpts().ProductName;
739a9909d23SDaniel Grumberg 
740a9909d23SDaniel Grumberg   // Now that we have enough information about the language options and the
741a9909d23SDaniel Grumberg   // target triple, let's create the APISet before anyone uses it.
742a9909d23SDaniel Grumberg   API = std::make_unique<APISet>(
743a9909d23SDaniel Grumberg       CI.getTarget().getTriple(),
744a9909d23SDaniel Grumberg       CI.getFrontendOpts().Inputs.back().getKind().getLanguage());
745a9909d23SDaniel Grumberg 
746*2966f0faSZixu Wang   auto LCF = std::make_unique<LocationFileChecker>(CI.getSourceManager(),
747*2966f0faSZixu Wang                                                    KnownInputFiles);
748aebe5fc6SDaniel Grumberg 
74910155922SDaniel Grumberg   CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
75010155922SDaniel Grumberg       CI.getSourceManager(), *LCF, *API, CI.getPreprocessor()));
751529a0570SDaniel Grumberg 
752aebe5fc6SDaniel Grumberg   return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
753aebe5fc6SDaniel Grumberg                                               std::move(LCF), *API);
75489f6b26fSZixu Wang }
75589f6b26fSZixu Wang 
756f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
757f833aab0SDaniel Grumberg   auto &Inputs = CI.getFrontendOpts().Inputs;
758f833aab0SDaniel Grumberg   if (Inputs.empty())
759f833aab0SDaniel Grumberg     return true;
760f833aab0SDaniel Grumberg 
761f833aab0SDaniel Grumberg   auto Kind = Inputs[0].getKind();
762f833aab0SDaniel Grumberg 
763f833aab0SDaniel Grumberg   // Convert the header file inputs into a single input buffer.
764f833aab0SDaniel Grumberg   SmallString<256> HeaderContents;
765f833aab0SDaniel Grumberg   for (const FrontendInputFile &FIF : Inputs) {
766f833aab0SDaniel Grumberg     if (Kind.isObjectiveC())
767f833aab0SDaniel Grumberg       HeaderContents += "#import";
768f833aab0SDaniel Grumberg     else
769f833aab0SDaniel Grumberg       HeaderContents += "#include";
7704c262feeSZixu Wang     HeaderContents += " \"";
771*2966f0faSZixu Wang     HeaderContents += FIF.getFile();
7724c262feeSZixu Wang     HeaderContents += "\"\n";
7734c262feeSZixu Wang 
774*2966f0faSZixu Wang     KnownInputFiles.emplace_back(FIF.getFile());
775*2966f0faSZixu Wang   }
776f833aab0SDaniel Grumberg 
777985eaa1aSDaniel Grumberg   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
778f833aab0SDaniel Grumberg                                                 getInputBufferName());
779f833aab0SDaniel Grumberg 
780f833aab0SDaniel Grumberg   // Set that buffer up as our "real" input in the CompilerInstance.
781f833aab0SDaniel Grumberg   Inputs.clear();
782f833aab0SDaniel Grumberg   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
783f833aab0SDaniel Grumberg 
784f833aab0SDaniel Grumberg   return true;
785f833aab0SDaniel Grumberg }
786f833aab0SDaniel Grumberg 
787a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() {
788a9909d23SDaniel Grumberg   if (!OS)
789a9909d23SDaniel Grumberg     return;
790a9909d23SDaniel Grumberg 
791a9909d23SDaniel Grumberg   // Setup a SymbolGraphSerializer to write out collected API information in
792a9909d23SDaniel Grumberg   // the Symbol Graph format.
793a9909d23SDaniel Grumberg   // FIXME: Make the kind of APISerializer configurable.
794a9909d23SDaniel Grumberg   SymbolGraphSerializer SGSerializer(*API, ProductName);
795a9909d23SDaniel Grumberg   SGSerializer.serialize(*OS);
7962d133867SDuncan P. N. Exon Smith   OS.reset();
797a9909d23SDaniel Grumberg }
798a9909d23SDaniel Grumberg 
79989f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream>
80089f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
80189f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS =
80289f6b26fSZixu Wang       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
80389f6b26fSZixu Wang                                  /*RemoveFileOnSignal=*/false);
80489f6b26fSZixu Wang   if (!OS)
80589f6b26fSZixu Wang     return nullptr;
80689f6b26fSZixu Wang   return OS;
80789f6b26fSZixu Wang }
808