189f6b26fSZixu Wang //===- ExtractAPI/ExtractAPIConsumer.cpp ------------------------*- C++ -*-===//
289f6b26fSZixu Wang //
389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information.
589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
689f6b26fSZixu Wang //
789f6b26fSZixu Wang //===----------------------------------------------------------------------===//
889f6b26fSZixu Wang ///
989f6b26fSZixu Wang /// \file
1089f6b26fSZixu Wang /// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to
1189f6b26fSZixu Wang /// collect API information.
1289f6b26fSZixu Wang ///
1389f6b26fSZixu Wang //===----------------------------------------------------------------------===//
1489f6b26fSZixu Wang 
1589f6b26fSZixu Wang #include "clang/AST/ASTConsumer.h"
1689f6b26fSZixu Wang #include "clang/AST/ASTContext.h"
1789f6b26fSZixu Wang #include "clang/AST/Decl.h"
1889f6b26fSZixu Wang #include "clang/AST/DeclCXX.h"
1989f6b26fSZixu Wang #include "clang/AST/ParentMapContext.h"
2089f6b26fSZixu Wang #include "clang/AST/RawCommentList.h"
2189f6b26fSZixu Wang #include "clang/AST/RecursiveASTVisitor.h"
2289f6b26fSZixu Wang #include "clang/Basic/TargetInfo.h"
2389f6b26fSZixu Wang #include "clang/ExtractAPI/API.h"
2489f6b26fSZixu Wang #include "clang/ExtractAPI/AvailabilityInfo.h"
2589f6b26fSZixu Wang #include "clang/ExtractAPI/DeclarationFragments.h"
2689f6b26fSZixu Wang #include "clang/ExtractAPI/FrontendActions.h"
2789f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
2889f6b26fSZixu Wang #include "clang/Frontend/ASTConsumers.h"
2989f6b26fSZixu Wang #include "clang/Frontend/CompilerInstance.h"
30f833aab0SDaniel Grumberg #include "clang/Frontend/FrontendOptions.h"
31529a0570SDaniel Grumberg #include "clang/Lex/MacroInfo.h"
32529a0570SDaniel Grumberg #include "clang/Lex/PPCallbacks.h"
33529a0570SDaniel Grumberg #include "clang/Lex/PreprocessorOptions.h"
34529a0570SDaniel Grumberg #include "llvm/ADT/STLExtras.h"
35f833aab0SDaniel Grumberg #include "llvm/ADT/SmallVector.h"
36f833aab0SDaniel Grumberg #include "llvm/Support/MemoryBuffer.h"
3789f6b26fSZixu Wang #include "llvm/Support/raw_ostream.h"
3889f6b26fSZixu Wang 
3989f6b26fSZixu Wang using namespace clang;
4089f6b26fSZixu Wang using namespace extractapi;
4189f6b26fSZixu Wang 
4289f6b26fSZixu Wang namespace {
4389f6b26fSZixu Wang 
4489f6b26fSZixu Wang /// The RecursiveASTVisitor to traverse symbol declarations and collect API
4589f6b26fSZixu Wang /// information.
4689f6b26fSZixu Wang class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
4789f6b26fSZixu Wang public:
48a9909d23SDaniel Grumberg   ExtractAPIVisitor(ASTContext &Context, APISet &API)
49a9909d23SDaniel Grumberg       : Context(Context), API(API) {}
5089f6b26fSZixu Wang 
5189f6b26fSZixu Wang   const APISet &getAPI() const { return API; }
5289f6b26fSZixu Wang 
5389f6b26fSZixu Wang   bool VisitVarDecl(const VarDecl *Decl) {
5489f6b26fSZixu Wang     // Skip function parameters.
5589f6b26fSZixu Wang     if (isa<ParmVarDecl>(Decl))
5689f6b26fSZixu Wang       return true;
5789f6b26fSZixu Wang 
5889f6b26fSZixu Wang     // Skip non-global variables in records (struct/union/class).
5989f6b26fSZixu Wang     if (Decl->getDeclContext()->isRecord())
6089f6b26fSZixu Wang       return true;
6189f6b26fSZixu Wang 
6289f6b26fSZixu Wang     // Skip local variables inside function or method.
6389f6b26fSZixu Wang     if (!Decl->isDefinedOutsideFunctionOrMethod())
6489f6b26fSZixu Wang       return true;
6589f6b26fSZixu Wang 
6689f6b26fSZixu Wang     // If this is a template but not specialization or instantiation, skip.
6789f6b26fSZixu Wang     if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
6889f6b26fSZixu Wang         Decl->getTemplateSpecializationKind() == TSK_Undeclared)
6989f6b26fSZixu Wang       return true;
7089f6b26fSZixu Wang 
7189f6b26fSZixu Wang     // Collect symbol information.
7289f6b26fSZixu Wang     StringRef Name = Decl->getName();
7389f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
7489f6b26fSZixu Wang     PresumedLoc Loc =
7589f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
7689f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
7789f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
7889f6b26fSZixu Wang     DocComment Comment;
7989f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
8089f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
8189f6b26fSZixu Wang                                               Context.getDiagnostics());
8289f6b26fSZixu Wang 
8389f6b26fSZixu Wang     // Build declaration fragments and sub-heading for the variable.
8489f6b26fSZixu Wang     DeclarationFragments Declaration =
8589f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
8689f6b26fSZixu Wang     DeclarationFragments SubHeading =
8789f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
8889f6b26fSZixu Wang 
8989f6b26fSZixu Wang     // Add the global variable record to the API set.
9089f6b26fSZixu Wang     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
9189f6b26fSZixu Wang                      Declaration, SubHeading);
9289f6b26fSZixu Wang     return true;
9389f6b26fSZixu Wang   }
9489f6b26fSZixu Wang 
9589f6b26fSZixu Wang   bool VisitFunctionDecl(const FunctionDecl *Decl) {
9689f6b26fSZixu Wang     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
9789f6b26fSZixu Wang       // Skip member function in class templates.
9889f6b26fSZixu Wang       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
9989f6b26fSZixu Wang         return true;
10089f6b26fSZixu Wang 
10189f6b26fSZixu Wang       // Skip methods in records.
10289f6b26fSZixu Wang       for (auto P : Context.getParents(*Method)) {
10389f6b26fSZixu Wang         if (P.get<CXXRecordDecl>())
10489f6b26fSZixu Wang           return true;
10589f6b26fSZixu Wang       }
10689f6b26fSZixu Wang 
10789f6b26fSZixu Wang       // Skip ConstructorDecl and DestructorDecl.
10889f6b26fSZixu Wang       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
10989f6b26fSZixu Wang         return true;
11089f6b26fSZixu Wang     }
11189f6b26fSZixu Wang 
11289f6b26fSZixu Wang     // Skip templated functions.
11389f6b26fSZixu Wang     switch (Decl->getTemplatedKind()) {
11489f6b26fSZixu Wang     case FunctionDecl::TK_NonTemplate:
11589f6b26fSZixu Wang       break;
11689f6b26fSZixu Wang     case FunctionDecl::TK_MemberSpecialization:
11789f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplateSpecialization:
11889f6b26fSZixu Wang       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
11989f6b26fSZixu Wang         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
12089f6b26fSZixu Wang           return true;
12189f6b26fSZixu Wang       }
12289f6b26fSZixu Wang       break;
12389f6b26fSZixu Wang     case FunctionDecl::TK_FunctionTemplate:
12489f6b26fSZixu Wang     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
12589f6b26fSZixu Wang       return true;
12689f6b26fSZixu Wang     }
12789f6b26fSZixu Wang 
12889f6b26fSZixu Wang     // Collect symbol information.
12989f6b26fSZixu Wang     StringRef Name = Decl->getName();
13089f6b26fSZixu Wang     StringRef USR = API.recordUSR(Decl);
13189f6b26fSZixu Wang     PresumedLoc Loc =
13289f6b26fSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
13389f6b26fSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
13489f6b26fSZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
13589f6b26fSZixu Wang     DocComment Comment;
13689f6b26fSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
13789f6b26fSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
13889f6b26fSZixu Wang                                               Context.getDiagnostics());
13989f6b26fSZixu Wang 
14089f6b26fSZixu Wang     // Build declaration fragments, sub-heading, and signature of the function.
14189f6b26fSZixu Wang     DeclarationFragments Declaration =
14289f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
14389f6b26fSZixu Wang     DeclarationFragments SubHeading =
14489f6b26fSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
14589f6b26fSZixu Wang     FunctionSignature Signature =
14689f6b26fSZixu Wang         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
14789f6b26fSZixu Wang 
14889f6b26fSZixu Wang     // Add the function record to the API set.
14989f6b26fSZixu Wang     API.addFunction(Name, USR, Loc, Availability, Linkage, Comment, Declaration,
15089f6b26fSZixu Wang                     SubHeading, Signature);
15189f6b26fSZixu Wang     return true;
15289f6b26fSZixu Wang   }
15389f6b26fSZixu Wang 
15471b4c226SZixu Wang   bool VisitEnumDecl(const EnumDecl *Decl) {
15571b4c226SZixu Wang     if (!Decl->isComplete())
15671b4c226SZixu Wang       return true;
15771b4c226SZixu Wang 
15871b4c226SZixu Wang     // Skip forward declaration.
15971b4c226SZixu Wang     if (!Decl->isThisDeclarationADefinition())
16071b4c226SZixu Wang       return true;
16171b4c226SZixu Wang 
16271b4c226SZixu Wang     // Collect symbol information.
16371b4c226SZixu Wang     StringRef Name = Decl->getName();
16471b4c226SZixu Wang     StringRef USR = API.recordUSR(Decl);
16571b4c226SZixu Wang     PresumedLoc Loc =
16671b4c226SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
16771b4c226SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
16871b4c226SZixu Wang     DocComment Comment;
16971b4c226SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
17071b4c226SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
17171b4c226SZixu Wang                                               Context.getDiagnostics());
17271b4c226SZixu Wang 
17371b4c226SZixu Wang     // Build declaration fragments and sub-heading for the enum.
17471b4c226SZixu Wang     DeclarationFragments Declaration =
17571b4c226SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
17671b4c226SZixu Wang     DeclarationFragments SubHeading =
17771b4c226SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
17871b4c226SZixu Wang 
17971b4c226SZixu Wang     EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
18071b4c226SZixu Wang                                          Declaration, SubHeading);
18171b4c226SZixu Wang 
18271b4c226SZixu Wang     // Now collect information about the enumerators in this enum.
18371b4c226SZixu Wang     recordEnumConstants(EnumRecord, Decl->enumerators());
18471b4c226SZixu Wang 
18571b4c226SZixu Wang     return true;
18671b4c226SZixu Wang   }
18771b4c226SZixu Wang 
1885bb5704cSZixu Wang   bool VisitRecordDecl(const RecordDecl *Decl) {
1895bb5704cSZixu Wang     if (!Decl->isCompleteDefinition())
1905bb5704cSZixu Wang       return true;
1915bb5704cSZixu Wang 
1925bb5704cSZixu Wang     // Skip C++ structs/classes/unions
1935bb5704cSZixu Wang     // TODO: support C++ records
1945bb5704cSZixu Wang     if (isa<CXXRecordDecl>(Decl))
1955bb5704cSZixu Wang       return true;
1965bb5704cSZixu Wang 
1975bb5704cSZixu Wang     // Collect symbol information.
1985bb5704cSZixu Wang     StringRef Name = Decl->getName();
1995bb5704cSZixu Wang     StringRef USR = API.recordUSR(Decl);
2005bb5704cSZixu Wang     PresumedLoc Loc =
2015bb5704cSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2025bb5704cSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2035bb5704cSZixu Wang     DocComment Comment;
2045bb5704cSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2055bb5704cSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2065bb5704cSZixu Wang                                               Context.getDiagnostics());
2075bb5704cSZixu Wang 
2085bb5704cSZixu Wang     // Build declaration fragments and sub-heading for the struct.
2095bb5704cSZixu Wang     DeclarationFragments Declaration =
2105bb5704cSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
2115bb5704cSZixu Wang     DeclarationFragments SubHeading =
2125bb5704cSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2135bb5704cSZixu Wang 
2145bb5704cSZixu Wang     StructRecord *StructRecord = API.addStruct(
2155bb5704cSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
2165bb5704cSZixu Wang 
2175bb5704cSZixu Wang     // Now collect information about the fields in this struct.
2185bb5704cSZixu Wang     recordStructFields(StructRecord, Decl->fields());
2195bb5704cSZixu Wang 
2205bb5704cSZixu Wang     return true;
2215bb5704cSZixu Wang   }
2225bb5704cSZixu Wang 
2239b36e126SZixu Wang   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
2249b36e126SZixu Wang     // Skip forward declaration for classes (@class)
2259b36e126SZixu Wang     if (!Decl->isThisDeclarationADefinition())
2269b36e126SZixu Wang       return true;
2279b36e126SZixu Wang 
2289b36e126SZixu Wang     // Collect symbol information.
2299b36e126SZixu Wang     StringRef Name = Decl->getName();
2309b36e126SZixu Wang     StringRef USR = API.recordUSR(Decl);
2319b36e126SZixu Wang     PresumedLoc Loc =
2329b36e126SZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
2339b36e126SZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
2349b36e126SZixu Wang     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
2359b36e126SZixu Wang     DocComment Comment;
2369b36e126SZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
2379b36e126SZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
2389b36e126SZixu Wang                                               Context.getDiagnostics());
2399b36e126SZixu Wang 
2409b36e126SZixu Wang     // Build declaration fragments and sub-heading for the interface.
2419b36e126SZixu Wang     DeclarationFragments Declaration =
2429b36e126SZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
2439b36e126SZixu Wang     DeclarationFragments SubHeading =
2449b36e126SZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
2459b36e126SZixu Wang 
2469b36e126SZixu Wang     // Collect super class information.
2479b36e126SZixu Wang     SymbolReference SuperClass;
2489b36e126SZixu Wang     if (const auto *SuperClassDecl = Decl->getSuperClass()) {
2499b36e126SZixu Wang       SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
2509b36e126SZixu Wang       SuperClass.USR = API.recordUSR(SuperClassDecl);
2519b36e126SZixu Wang     }
2529b36e126SZixu Wang 
2539b36e126SZixu Wang     ObjCInterfaceRecord *ObjCInterfaceRecord =
2549b36e126SZixu Wang         API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
2559b36e126SZixu Wang                              Declaration, SubHeading, SuperClass);
2569b36e126SZixu Wang 
2579b36e126SZixu Wang     // Record all methods (selectors). This doesn't include automatically
2589b36e126SZixu Wang     // synthesized property methods.
2599b36e126SZixu Wang     recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
2609b36e126SZixu Wang     recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
2619b36e126SZixu Wang     recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
2629b36e126SZixu Wang     recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
2639b36e126SZixu Wang 
2649b36e126SZixu Wang     return true;
2659b36e126SZixu Wang   }
2669b36e126SZixu Wang 
267d1d34bafSZixu Wang   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
268d1d34bafSZixu Wang     // Skip forward declaration for protocols (@protocol).
269d1d34bafSZixu Wang     if (!Decl->isThisDeclarationADefinition())
270d1d34bafSZixu Wang       return true;
271d1d34bafSZixu Wang 
272d1d34bafSZixu Wang     // Collect symbol information.
273d1d34bafSZixu Wang     StringRef Name = Decl->getName();
274d1d34bafSZixu Wang     StringRef USR = API.recordUSR(Decl);
275d1d34bafSZixu Wang     PresumedLoc Loc =
276d1d34bafSZixu Wang         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
277d1d34bafSZixu Wang     AvailabilityInfo Availability = getAvailability(Decl);
278d1d34bafSZixu Wang     DocComment Comment;
279d1d34bafSZixu Wang     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
280d1d34bafSZixu Wang       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
281d1d34bafSZixu Wang                                               Context.getDiagnostics());
282d1d34bafSZixu Wang 
283d1d34bafSZixu Wang     // Build declaration fragments and sub-heading for the protocol.
284d1d34bafSZixu Wang     DeclarationFragments Declaration =
285d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
286d1d34bafSZixu Wang     DeclarationFragments SubHeading =
287d1d34bafSZixu Wang         DeclarationFragmentsBuilder::getSubHeading(Decl);
288d1d34bafSZixu Wang 
289d1d34bafSZixu Wang     ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
290d1d34bafSZixu Wang         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
291d1d34bafSZixu Wang 
292d1d34bafSZixu Wang     recordObjCMethods(ObjCProtocolRecord, Decl->methods());
293d1d34bafSZixu Wang     recordObjCProperties(ObjCProtocolRecord, Decl->properties());
294d1d34bafSZixu Wang     recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
295d1d34bafSZixu Wang 
296d1d34bafSZixu Wang     return true;
297d1d34bafSZixu Wang   }
298d1d34bafSZixu Wang 
29989f6b26fSZixu Wang private:
30089f6b26fSZixu Wang   /// Get availability information of the declaration \p D.
30189f6b26fSZixu Wang   AvailabilityInfo getAvailability(const Decl *D) const {
30289f6b26fSZixu Wang     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
30389f6b26fSZixu Wang 
30489f6b26fSZixu Wang     AvailabilityInfo Availability;
30589f6b26fSZixu Wang     // Collect availability attributes from all redeclarations.
30689f6b26fSZixu Wang     for (const auto *RD : D->redecls()) {
30789f6b26fSZixu Wang       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
30889f6b26fSZixu Wang         if (A->getPlatform()->getName() != PlatformName)
30989f6b26fSZixu Wang           continue;
31089f6b26fSZixu Wang         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
31189f6b26fSZixu Wang                                         A->getObsoleted(), A->getUnavailable(),
31289f6b26fSZixu Wang                                         /* UnconditionallyDeprecated */ false,
31389f6b26fSZixu Wang                                         /* UnconditionallyUnavailable */ false);
31489f6b26fSZixu Wang         break;
31589f6b26fSZixu Wang       }
31689f6b26fSZixu Wang 
31789f6b26fSZixu Wang       if (const auto *A = RD->getAttr<UnavailableAttr>())
31889f6b26fSZixu Wang         if (!A->isImplicit()) {
31989f6b26fSZixu Wang           Availability.Unavailable = true;
32089f6b26fSZixu Wang           Availability.UnconditionallyUnavailable = true;
32189f6b26fSZixu Wang         }
32289f6b26fSZixu Wang 
32389f6b26fSZixu Wang       if (const auto *A = RD->getAttr<DeprecatedAttr>())
32489f6b26fSZixu Wang         if (!A->isImplicit())
32589f6b26fSZixu Wang           Availability.UnconditionallyDeprecated = true;
32689f6b26fSZixu Wang     }
32789f6b26fSZixu Wang 
32889f6b26fSZixu Wang     return Availability;
32989f6b26fSZixu Wang   }
33089f6b26fSZixu Wang 
33171b4c226SZixu Wang   /// Collect API information for the enum constants and associate with the
33271b4c226SZixu Wang   /// parent enum.
33371b4c226SZixu Wang   void recordEnumConstants(EnumRecord *EnumRecord,
33471b4c226SZixu Wang                            const EnumDecl::enumerator_range Constants) {
33571b4c226SZixu Wang     for (const auto *Constant : Constants) {
33671b4c226SZixu Wang       // Collect symbol information.
33771b4c226SZixu Wang       StringRef Name = Constant->getName();
33871b4c226SZixu Wang       StringRef USR = API.recordUSR(Constant);
33971b4c226SZixu Wang       PresumedLoc Loc =
34071b4c226SZixu Wang           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
34171b4c226SZixu Wang       AvailabilityInfo Availability = getAvailability(Constant);
34271b4c226SZixu Wang       DocComment Comment;
34371b4c226SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
34471b4c226SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
34571b4c226SZixu Wang                                                 Context.getDiagnostics());
34671b4c226SZixu Wang 
34771b4c226SZixu Wang       // Build declaration fragments and sub-heading for the enum constant.
34871b4c226SZixu Wang       DeclarationFragments Declaration =
34971b4c226SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
35071b4c226SZixu Wang       DeclarationFragments SubHeading =
35171b4c226SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Constant);
35271b4c226SZixu Wang 
35371b4c226SZixu Wang       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
35471b4c226SZixu Wang                           Declaration, SubHeading);
35571b4c226SZixu Wang     }
35671b4c226SZixu Wang   }
35771b4c226SZixu Wang 
3585bb5704cSZixu Wang   /// Collect API information for the struct fields and associate with the
3595bb5704cSZixu Wang   /// parent struct.
3605bb5704cSZixu Wang   void recordStructFields(StructRecord *StructRecord,
3615bb5704cSZixu Wang                           const RecordDecl::field_range Fields) {
3625bb5704cSZixu Wang     for (const auto *Field : Fields) {
3635bb5704cSZixu Wang       // Collect symbol information.
3645bb5704cSZixu Wang       StringRef Name = Field->getName();
3655bb5704cSZixu Wang       StringRef USR = API.recordUSR(Field);
3665bb5704cSZixu Wang       PresumedLoc Loc =
3675bb5704cSZixu Wang           Context.getSourceManager().getPresumedLoc(Field->getLocation());
3685bb5704cSZixu Wang       AvailabilityInfo Availability = getAvailability(Field);
3695bb5704cSZixu Wang       DocComment Comment;
3705bb5704cSZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
3715bb5704cSZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
3725bb5704cSZixu Wang                                                 Context.getDiagnostics());
3735bb5704cSZixu Wang 
3745bb5704cSZixu Wang       // Build declaration fragments and sub-heading for the struct field.
3755bb5704cSZixu Wang       DeclarationFragments Declaration =
3765bb5704cSZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Field);
3775bb5704cSZixu Wang       DeclarationFragments SubHeading =
3785bb5704cSZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Field);
3795bb5704cSZixu Wang 
3805bb5704cSZixu Wang       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
3815bb5704cSZixu Wang                          Declaration, SubHeading);
3825bb5704cSZixu Wang     }
3835bb5704cSZixu Wang   }
3845bb5704cSZixu Wang 
3859b36e126SZixu Wang   /// Collect API information for the Objective-C methods and associate with the
3869b36e126SZixu Wang   /// parent container.
3879b36e126SZixu Wang   void recordObjCMethods(ObjCContainerRecord *Container,
3889b36e126SZixu Wang                          const ObjCContainerDecl::method_range Methods) {
3899b36e126SZixu Wang     for (const auto *Method : Methods) {
3909b36e126SZixu Wang       // Don't record selectors for properties.
3919b36e126SZixu Wang       if (Method->isPropertyAccessor())
3929b36e126SZixu Wang         continue;
3939b36e126SZixu Wang 
3949b36e126SZixu Wang       StringRef Name = API.copyString(Method->getSelector().getAsString());
3959b36e126SZixu Wang       StringRef USR = API.recordUSR(Method);
3969b36e126SZixu Wang       PresumedLoc Loc =
3979b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Method->getLocation());
3989b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Method);
3999b36e126SZixu Wang       DocComment Comment;
4009b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
4019b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
4029b36e126SZixu Wang                                                 Context.getDiagnostics());
4039b36e126SZixu Wang 
4049b36e126SZixu Wang       // Build declaration fragments, sub-heading, and signature for the method.
4059b36e126SZixu Wang       DeclarationFragments Declaration =
4069b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
4079b36e126SZixu Wang       DeclarationFragments SubHeading =
4089b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Method);
4099b36e126SZixu Wang       FunctionSignature Signature =
4109b36e126SZixu Wang           DeclarationFragmentsBuilder::getFunctionSignature(Method);
4119b36e126SZixu Wang 
4129b36e126SZixu Wang       API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
4139b36e126SZixu Wang                         Declaration, SubHeading, Signature,
4149b36e126SZixu Wang                         Method->isInstanceMethod());
4159b36e126SZixu Wang     }
4169b36e126SZixu Wang   }
4179b36e126SZixu Wang 
4189b36e126SZixu Wang   void recordObjCProperties(ObjCContainerRecord *Container,
4199b36e126SZixu Wang                             const ObjCContainerDecl::prop_range Properties) {
4209b36e126SZixu Wang     for (const auto *Property : Properties) {
4219b36e126SZixu Wang       StringRef Name = Property->getName();
4229b36e126SZixu Wang       StringRef USR = API.recordUSR(Property);
4239b36e126SZixu Wang       PresumedLoc Loc =
4249b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Property->getLocation());
4259b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Property);
4269b36e126SZixu Wang       DocComment Comment;
4279b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
4289b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
4299b36e126SZixu Wang                                                 Context.getDiagnostics());
4309b36e126SZixu Wang 
4319b36e126SZixu Wang       // Build declaration fragments and sub-heading for the property.
4329b36e126SZixu Wang       DeclarationFragments Declaration =
4339b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
4349b36e126SZixu Wang       DeclarationFragments SubHeading =
4359b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Property);
4369b36e126SZixu Wang 
4379b36e126SZixu Wang       StringRef GetterName =
4389b36e126SZixu Wang           API.copyString(Property->getGetterName().getAsString());
4399b36e126SZixu Wang       StringRef SetterName =
4409b36e126SZixu Wang           API.copyString(Property->getSetterName().getAsString());
4419b36e126SZixu Wang 
4429b36e126SZixu Wang       // Get the attributes for property.
4439b36e126SZixu Wang       unsigned Attributes = ObjCPropertyRecord::NoAttr;
4449b36e126SZixu Wang       if (Property->getPropertyAttributes() &
4459b36e126SZixu Wang           ObjCPropertyAttribute::kind_readonly)
4469b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::ReadOnly;
4479b36e126SZixu Wang       if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
4489b36e126SZixu Wang         Attributes |= ObjCPropertyRecord::Class;
4499b36e126SZixu Wang 
4509b36e126SZixu Wang       API.addObjCProperty(
4519b36e126SZixu Wang           Container, Name, USR, Loc, Availability, Comment, Declaration,
4529b36e126SZixu Wang           SubHeading,
4539b36e126SZixu Wang           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
4549b36e126SZixu Wang           GetterName, SetterName, Property->isOptional());
4559b36e126SZixu Wang     }
4569b36e126SZixu Wang   }
4579b36e126SZixu Wang 
4589b36e126SZixu Wang   void recordObjCInstanceVariables(
4599b36e126SZixu Wang       ObjCContainerRecord *Container,
4609b36e126SZixu Wang       const llvm::iterator_range<
4619b36e126SZixu Wang           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
4629b36e126SZixu Wang           Ivars) {
4639b36e126SZixu Wang     for (const auto *Ivar : Ivars) {
4649b36e126SZixu Wang       StringRef Name = Ivar->getName();
4659b36e126SZixu Wang       StringRef USR = API.recordUSR(Ivar);
4669b36e126SZixu Wang       PresumedLoc Loc =
4679b36e126SZixu Wang           Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
4689b36e126SZixu Wang       AvailabilityInfo Availability = getAvailability(Ivar);
4699b36e126SZixu Wang       DocComment Comment;
4709b36e126SZixu Wang       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
4719b36e126SZixu Wang         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
4729b36e126SZixu Wang                                                 Context.getDiagnostics());
4739b36e126SZixu Wang 
4749b36e126SZixu Wang       // Build declaration fragments and sub-heading for the instance variable.
4759b36e126SZixu Wang       DeclarationFragments Declaration =
4769b36e126SZixu Wang           DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
4779b36e126SZixu Wang       DeclarationFragments SubHeading =
4789b36e126SZixu Wang           DeclarationFragmentsBuilder::getSubHeading(Ivar);
4799b36e126SZixu Wang 
4809b36e126SZixu Wang       ObjCInstanceVariableRecord::AccessControl Access =
4819b36e126SZixu Wang           Ivar->getCanonicalAccessControl();
4829b36e126SZixu Wang 
4839b36e126SZixu Wang       API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
4849b36e126SZixu Wang                                   Comment, Declaration, SubHeading, Access);
4859b36e126SZixu Wang     }
4869b36e126SZixu Wang   }
4879b36e126SZixu Wang 
4889b36e126SZixu Wang   void recordObjCProtocols(ObjCContainerRecord *Container,
4899b36e126SZixu Wang                            ObjCInterfaceDecl::protocol_range Protocols) {
4909b36e126SZixu Wang     for (const auto *Protocol : Protocols)
4919b36e126SZixu Wang       Container->Protocols.emplace_back(Protocol->getName(),
4929b36e126SZixu Wang                                         API.recordUSR(Protocol));
4939b36e126SZixu Wang   }
4949b36e126SZixu Wang 
49589f6b26fSZixu Wang   ASTContext &Context;
496a9909d23SDaniel Grumberg   APISet &API;
49789f6b26fSZixu Wang };
49889f6b26fSZixu Wang 
49989f6b26fSZixu Wang class ExtractAPIConsumer : public ASTConsumer {
50089f6b26fSZixu Wang public:
501a9909d23SDaniel Grumberg   ExtractAPIConsumer(ASTContext &Context, APISet &API)
502a9909d23SDaniel Grumberg       : Visitor(Context, API) {}
50389f6b26fSZixu Wang 
50489f6b26fSZixu Wang   void HandleTranslationUnit(ASTContext &Context) override {
50589f6b26fSZixu Wang     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
50689f6b26fSZixu Wang     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
50789f6b26fSZixu Wang   }
50889f6b26fSZixu Wang 
50989f6b26fSZixu Wang private:
51089f6b26fSZixu Wang   ExtractAPIVisitor Visitor;
51189f6b26fSZixu Wang };
51289f6b26fSZixu Wang 
513529a0570SDaniel Grumberg class MacroCallback : public PPCallbacks {
514529a0570SDaniel Grumberg public:
515529a0570SDaniel Grumberg   MacroCallback(const SourceManager &SM, APISet &API) : SM(SM), API(API) {}
516529a0570SDaniel Grumberg 
517529a0570SDaniel Grumberg   void MacroDefined(const Token &MacroNameToken,
518529a0570SDaniel Grumberg                     const MacroDirective *MD) override {
519529a0570SDaniel Grumberg     auto *MacroInfo = MD->getMacroInfo();
520529a0570SDaniel Grumberg 
521529a0570SDaniel Grumberg     if (MacroInfo->isBuiltinMacro())
522529a0570SDaniel Grumberg       return;
523529a0570SDaniel Grumberg 
524529a0570SDaniel Grumberg     auto SourceLoc = MacroNameToken.getLocation();
525529a0570SDaniel Grumberg     if (SM.isWrittenInBuiltinFile(SourceLoc) ||
526529a0570SDaniel Grumberg         SM.isWrittenInCommandLineFile(SourceLoc))
527529a0570SDaniel Grumberg       return;
528529a0570SDaniel Grumberg 
529529a0570SDaniel Grumberg     PendingMacros.emplace_back(MacroNameToken, MD);
530529a0570SDaniel Grumberg   }
531529a0570SDaniel Grumberg 
532529a0570SDaniel Grumberg   // If a macro gets undefined at some point during preprocessing of the inputs
533529a0570SDaniel Grumberg   // it means that it isn't an exposed API and we should therefore not add a
534529a0570SDaniel Grumberg   // macro definition for it.
535529a0570SDaniel Grumberg   void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD,
536529a0570SDaniel Grumberg                       const MacroDirective *Undef) override {
537529a0570SDaniel Grumberg     llvm::erase_if(PendingMacros, [&MD](const PendingMacro &PM) {
538529a0570SDaniel Grumberg       return MD.getMacroInfo()->getDefinitionLoc() ==
539529a0570SDaniel Grumberg              PM.MD->getMacroInfo()->getDefinitionLoc();
540529a0570SDaniel Grumberg     });
541529a0570SDaniel Grumberg   }
542529a0570SDaniel Grumberg 
543529a0570SDaniel Grumberg   void EndOfMainFile() override {
544529a0570SDaniel Grumberg     for (auto &PM : PendingMacros) {
545529a0570SDaniel Grumberg       // `isUsedForHeaderGuard` is only set when the preprocessor leaves the
546529a0570SDaniel Grumberg       // file so check for it here.
547529a0570SDaniel Grumberg       if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
548529a0570SDaniel Grumberg         continue;
549529a0570SDaniel Grumberg 
550529a0570SDaniel Grumberg       StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
551529a0570SDaniel Grumberg       PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation());
552529a0570SDaniel Grumberg       StringRef USR =
553529a0570SDaniel Grumberg           API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM);
554529a0570SDaniel Grumberg 
555529a0570SDaniel Grumberg       API.addMacroDefinition(
556529a0570SDaniel Grumberg           Name, USR, Loc,
557529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
558529a0570SDaniel Grumberg           DeclarationFragmentsBuilder::getSubHeadingForMacro(Name));
559529a0570SDaniel Grumberg     }
560529a0570SDaniel Grumberg 
561529a0570SDaniel Grumberg     PendingMacros.clear();
562529a0570SDaniel Grumberg   }
563529a0570SDaniel Grumberg 
564529a0570SDaniel Grumberg private:
565529a0570SDaniel Grumberg   struct PendingMacro {
566529a0570SDaniel Grumberg     Token MacroNameToken;
567529a0570SDaniel Grumberg     const MacroDirective *MD;
568529a0570SDaniel Grumberg 
569529a0570SDaniel Grumberg     PendingMacro(const Token &MacroNameToken, const MacroDirective *MD)
570529a0570SDaniel Grumberg         : MacroNameToken(MacroNameToken), MD(MD) {}
571529a0570SDaniel Grumberg   };
572529a0570SDaniel Grumberg 
573529a0570SDaniel Grumberg   const SourceManager &SM;
574529a0570SDaniel Grumberg   APISet &API;
575529a0570SDaniel Grumberg   llvm::SmallVector<PendingMacro> PendingMacros;
576529a0570SDaniel Grumberg };
577529a0570SDaniel Grumberg 
57889f6b26fSZixu Wang } // namespace
57989f6b26fSZixu Wang 
58089f6b26fSZixu Wang std::unique_ptr<ASTConsumer>
58189f6b26fSZixu Wang ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
582a9909d23SDaniel Grumberg   OS = CreateOutputFile(CI, InFile);
58389f6b26fSZixu Wang   if (!OS)
58489f6b26fSZixu Wang     return nullptr;
585a9909d23SDaniel Grumberg 
586a9909d23SDaniel Grumberg   ProductName = CI.getFrontendOpts().ProductName;
587a9909d23SDaniel Grumberg 
588a9909d23SDaniel Grumberg   // Now that we have enough information about the language options and the
589a9909d23SDaniel Grumberg   // target triple, let's create the APISet before anyone uses it.
590a9909d23SDaniel Grumberg   API = std::make_unique<APISet>(
591a9909d23SDaniel Grumberg       CI.getTarget().getTriple(),
592a9909d23SDaniel Grumberg       CI.getFrontendOpts().Inputs.back().getKind().getLanguage());
593a9909d23SDaniel Grumberg 
594529a0570SDaniel Grumberg   // Register preprocessor callbacks that will add macro definitions to API.
595529a0570SDaniel Grumberg   CI.getPreprocessor().addPPCallbacks(
596529a0570SDaniel Grumberg       std::make_unique<MacroCallback>(CI.getSourceManager(), *API));
597529a0570SDaniel Grumberg 
598a9909d23SDaniel Grumberg   return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(), *API);
59989f6b26fSZixu Wang }
60089f6b26fSZixu Wang 
601f833aab0SDaniel Grumberg bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
602f833aab0SDaniel Grumberg   auto &Inputs = CI.getFrontendOpts().Inputs;
603f833aab0SDaniel Grumberg   if (Inputs.empty())
604f833aab0SDaniel Grumberg     return true;
605f833aab0SDaniel Grumberg 
606f833aab0SDaniel Grumberg   auto Kind = Inputs[0].getKind();
607f833aab0SDaniel Grumberg 
608f833aab0SDaniel Grumberg   // Convert the header file inputs into a single input buffer.
609f833aab0SDaniel Grumberg   SmallString<256> HeaderContents;
610f833aab0SDaniel Grumberg   for (const FrontendInputFile &FIF : Inputs) {
611f833aab0SDaniel Grumberg     if (Kind.isObjectiveC())
612f833aab0SDaniel Grumberg       HeaderContents += "#import";
613f833aab0SDaniel Grumberg     else
614f833aab0SDaniel Grumberg       HeaderContents += "#include";
615f833aab0SDaniel Grumberg     HeaderContents += " \"";
616f833aab0SDaniel Grumberg     HeaderContents += FIF.getFile();
617f833aab0SDaniel Grumberg     HeaderContents += "\"\n";
618f833aab0SDaniel Grumberg   }
619f833aab0SDaniel Grumberg 
620*985eaa1aSDaniel Grumberg   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
621f833aab0SDaniel Grumberg                                                 getInputBufferName());
622f833aab0SDaniel Grumberg 
623f833aab0SDaniel Grumberg   // Set that buffer up as our "real" input in the CompilerInstance.
624f833aab0SDaniel Grumberg   Inputs.clear();
625f833aab0SDaniel Grumberg   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
626f833aab0SDaniel Grumberg 
627f833aab0SDaniel Grumberg   return true;
628f833aab0SDaniel Grumberg }
629f833aab0SDaniel Grumberg 
630a9909d23SDaniel Grumberg void ExtractAPIAction::EndSourceFileAction() {
631a9909d23SDaniel Grumberg   if (!OS)
632a9909d23SDaniel Grumberg     return;
633a9909d23SDaniel Grumberg 
634a9909d23SDaniel Grumberg   // Setup a SymbolGraphSerializer to write out collected API information in
635a9909d23SDaniel Grumberg   // the Symbol Graph format.
636a9909d23SDaniel Grumberg   // FIXME: Make the kind of APISerializer configurable.
637a9909d23SDaniel Grumberg   SymbolGraphSerializer SGSerializer(*API, ProductName);
638a9909d23SDaniel Grumberg   SGSerializer.serialize(*OS);
639a9909d23SDaniel Grumberg   OS->flush();
640a9909d23SDaniel Grumberg }
641a9909d23SDaniel Grumberg 
64289f6b26fSZixu Wang std::unique_ptr<raw_pwrite_stream>
64389f6b26fSZixu Wang ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
64489f6b26fSZixu Wang   std::unique_ptr<raw_pwrite_stream> OS =
64589f6b26fSZixu Wang       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
64689f6b26fSZixu Wang                                  /*RemoveFileOnSignal=*/false);
64789f6b26fSZixu Wang   if (!OS)
64889f6b26fSZixu Wang     return nullptr;
64989f6b26fSZixu Wang   return OS;
65089f6b26fSZixu Wang }
651