1 //===- ExtractAPI/ExtractAPIConsumer.cpp ------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to
11 /// collect API information.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "TypedefUnderlyingTypeResolver.h"
16 #include "clang/AST/ASTConsumer.h"
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/AST/ParentMapContext.h"
21 #include "clang/AST/RawCommentList.h"
22 #include "clang/AST/RecursiveASTVisitor.h"
23 #include "clang/Basic/SourceLocation.h"
24 #include "clang/Basic/SourceManager.h"
25 #include "clang/Basic/TargetInfo.h"
26 #include "clang/ExtractAPI/API.h"
27 #include "clang/ExtractAPI/AvailabilityInfo.h"
28 #include "clang/ExtractAPI/DeclarationFragments.h"
29 #include "clang/ExtractAPI/FrontendActions.h"
30 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
31 #include "clang/Frontend/ASTConsumers.h"
32 #include "clang/Frontend/CompilerInstance.h"
33 #include "clang/Frontend/FrontendOptions.h"
34 #include "clang/Lex/MacroInfo.h"
35 #include "clang/Lex/PPCallbacks.h"
36 #include "clang/Lex/Preprocessor.h"
37 #include "clang/Lex/PreprocessorOptions.h"
38 #include "llvm/ADT/DenseSet.h"
39 #include "llvm/ADT/STLExtras.h"
40 #include "llvm/ADT/SmallVector.h"
41 #include "llvm/Support/FileSystem.h"
42 #include "llvm/Support/MemoryBuffer.h"
43 #include "llvm/Support/Path.h"
44 #include "llvm/Support/Regex.h"
45 #include "llvm/Support/raw_ostream.h"
46 #include <memory>
47 #include <utility>
48 
49 using namespace clang;
50 using namespace extractapi;
51 
52 namespace {
53 
54 StringRef getTypedefName(const TagDecl *Decl) {
55   if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
56     return TypedefDecl->getName();
57 
58   return {};
59 }
60 
61 Optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
62                                              StringRef File,
63                                              bool *IsQuoted = nullptr) {
64   assert(CI.hasFileManager() &&
65          "CompilerInstance does not have a FileNamager!");
66 
67   using namespace llvm::sys;
68   // Matches framework include patterns
69   const llvm::Regex Rule("/(.+)\\.framework/(.+)?Headers/(.+)");
70 
71   const auto &FS = CI.getVirtualFileSystem();
72 
73   SmallString<128> FilePath(File.begin(), File.end());
74   FS.makeAbsolute(FilePath);
75   path::remove_dots(FilePath, true);
76   File = FilePath;
77 
78   // Checks whether `Dir` is a strict path prefix of `File`. If so returns
79   // the prefix length. Otherwise return 0.
80   auto CheckDir = [&](llvm::StringRef Dir) -> unsigned {
81     llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
82     FS.makeAbsolute(DirPath);
83     path::remove_dots(DirPath, true);
84     Dir = DirPath;
85     for (auto NI = path::begin(File), NE = path::end(File),
86               DI = path::begin(Dir), DE = path::end(Dir);
87          /*termination condition in loop*/; ++NI, ++DI) {
88       // '.' components in File are ignored.
89       while (NI != NE && *NI == ".")
90         ++NI;
91       if (NI == NE)
92         break;
93 
94       // '.' components in Dir are ignored.
95       while (DI != DE && *DI == ".")
96         ++DI;
97 
98       // Dir is a prefix of File, up to '.' components and choice of path
99       // separators.
100       if (DI == DE)
101         return NI - path::begin(File);
102 
103       // Consider all path separators equal.
104       if (NI->size() == 1 && DI->size() == 1 &&
105           path::is_separator(NI->front()) && path::is_separator(DI->front()))
106         continue;
107 
108       // Special case Apple .sdk folders since the search path is typically a
109       // symlink like `iPhoneSimulator14.5.sdk` while the file is instead
110       // located in `iPhoneSimulator.sdk` (the real folder).
111       if (NI->endswith(".sdk") && DI->endswith(".sdk")) {
112         StringRef NBasename = path::stem(*NI);
113         StringRef DBasename = path::stem(*DI);
114         if (DBasename.startswith(NBasename))
115           continue;
116       }
117 
118       if (*NI != *DI)
119         break;
120     }
121     return 0;
122   };
123 
124   unsigned PrefixLength = 0;
125 
126   // Go through the search paths and find the first one that is a prefix of
127   // the header.
128   for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries) {
129     // Note whether the match is found in a quoted entry.
130     if (IsQuoted)
131       *IsQuoted = Entry.Group == frontend::Quoted;
132 
133     if (auto EntryFile = CI.getFileManager().getOptionalFileRef(Entry.Path)) {
134       if (auto HMap = HeaderMap::Create(*EntryFile, CI.getFileManager())) {
135         // If this is a headermap entry, try to reverse lookup the full path
136         // for a spelled name before mapping.
137         StringRef SpelledFilename =
138             HMap->reverseLookupFilename(path::convert_to_slash(File));
139         if (!SpelledFilename.empty())
140           return SpelledFilename.str();
141 
142         // No matching mapping in this headermap, try next search entry.
143         continue;
144       }
145     }
146 
147     // Entry is a directory search entry, try to check if it's a prefix of File.
148     PrefixLength = CheckDir(Entry.Path);
149     if (PrefixLength > 0) {
150       // The header is found in a framework path, construct the framework-style
151       // include name `<Framework/Header.h>`
152       if (Entry.IsFramework) {
153         SmallVector<StringRef, 4> Matches;
154         // Convert the file path to forward slashes for matching the framework
155         // regex.
156         Rule.match(path::convert_to_slash(File), &Matches);
157         // Returned matches are always in stable order.
158         if (Matches.size() != 4)
159           return None;
160 
161         return path::convert_to_slash(
162             (Matches[1].drop_front(Matches[1].rfind('/') + 1) + "/" +
163              Matches[3])
164                 .str());
165 
166       }
167 
168       // The header is found in a normal search path, strip the search path
169       // prefix to get an include name.
170       return path::convert_to_slash(File.drop_front(PrefixLength));
171     }
172   }
173 
174   // Couldn't determine a include name, use full path instead.
175   return None;
176 }
177 
178 struct LocationFileChecker {
179   bool isLocationInKnownFile(SourceLocation Loc) {
180     // If the loc refers to a macro expansion we need to first get the file
181     // location of the expansion.
182     auto &SM = CI.getSourceManager();
183     auto FileLoc = SM.getFileLoc(Loc);
184     FileID FID = SM.getFileID(FileLoc);
185     if (FID.isInvalid())
186       return false;
187 
188     const auto *File = SM.getFileEntryForID(FID);
189     if (!File)
190       return false;
191 
192     if (KnownFileEntries.count(File))
193       return true;
194 
195     if (ExternalFileEntries.count(File))
196       return false;
197 
198     StringRef FileName = File->tryGetRealPathName().empty()
199                              ? File->getName()
200                              : File->tryGetRealPathName();
201 
202     // Try to reduce the include name the same way we tried to include it.
203     bool IsQuoted = false;
204     if (auto IncludeName = getRelativeIncludeName(CI, FileName, &IsQuoted))
205       if (llvm::find_if(KnownFiles,
206                         [&IsQuoted, &IncludeName](const auto &KnownFile) {
207                           return KnownFile.first.equals(*IncludeName) &&
208                                  KnownFile.second == IsQuoted;
209                         }) != KnownFiles.end()) {
210         KnownFileEntries.insert(File);
211         return true;
212       }
213 
214     // Record that the file was not found to avoid future reverse lookup for
215     // the same file.
216     ExternalFileEntries.insert(File);
217     return false;
218   }
219 
220   LocationFileChecker(const CompilerInstance &CI,
221                       SmallVector<std::pair<SmallString<32>, bool>> &KnownFiles)
222       : CI(CI), KnownFiles(KnownFiles), ExternalFileEntries() {
223     for (const auto &KnownFile : KnownFiles)
224       if (auto FileEntry = CI.getFileManager().getFile(KnownFile.first))
225         KnownFileEntries.insert(*FileEntry);
226   }
227 
228 private:
229   const CompilerInstance &CI;
230   SmallVector<std::pair<SmallString<32>, bool>> &KnownFiles;
231   llvm::DenseSet<const FileEntry *> KnownFileEntries;
232   llvm::DenseSet<const FileEntry *> ExternalFileEntries;
233 };
234 
235 /// The RecursiveASTVisitor to traverse symbol declarations and collect API
236 /// information.
237 class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
238 public:
239   ExtractAPIVisitor(ASTContext &Context, LocationFileChecker &LCF, APISet &API)
240       : Context(Context), API(API), LCF(LCF) {}
241 
242   const APISet &getAPI() const { return API; }
243 
244   bool VisitVarDecl(const VarDecl *Decl) {
245     // Skip function parameters.
246     if (isa<ParmVarDecl>(Decl))
247       return true;
248 
249     // Skip non-global variables in records (struct/union/class).
250     if (Decl->getDeclContext()->isRecord())
251       return true;
252 
253     // Skip local variables inside function or method.
254     if (!Decl->isDefinedOutsideFunctionOrMethod())
255       return true;
256 
257     // If this is a template but not specialization or instantiation, skip.
258     if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
259         Decl->getTemplateSpecializationKind() == TSK_Undeclared)
260       return true;
261 
262     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
263       return true;
264 
265     // Collect symbol information.
266     StringRef Name = Decl->getName();
267     StringRef USR = API.recordUSR(Decl);
268     PresumedLoc Loc =
269         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
270     AvailabilityInfo Availability = getAvailability(Decl);
271     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
272     DocComment Comment;
273     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
274       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
275                                               Context.getDiagnostics());
276 
277     // Build declaration fragments and sub-heading for the variable.
278     DeclarationFragments Declaration =
279         DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
280     DeclarationFragments SubHeading =
281         DeclarationFragmentsBuilder::getSubHeading(Decl);
282 
283     // Add the global variable record to the API set.
284     API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
285                      Declaration, SubHeading);
286     return true;
287   }
288 
289   bool VisitFunctionDecl(const FunctionDecl *Decl) {
290     if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
291       // Skip member function in class templates.
292       if (Method->getParent()->getDescribedClassTemplate() != nullptr)
293         return true;
294 
295       // Skip methods in records.
296       for (auto P : Context.getParents(*Method)) {
297         if (P.get<CXXRecordDecl>())
298           return true;
299       }
300 
301       // Skip ConstructorDecl and DestructorDecl.
302       if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
303         return true;
304     }
305 
306     // Skip templated functions.
307     switch (Decl->getTemplatedKind()) {
308     case FunctionDecl::TK_NonTemplate:
309       break;
310     case FunctionDecl::TK_MemberSpecialization:
311     case FunctionDecl::TK_FunctionTemplateSpecialization:
312       if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
313         if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
314           return true;
315       }
316       break;
317     case FunctionDecl::TK_FunctionTemplate:
318     case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
319       return true;
320     }
321 
322     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
323       return true;
324 
325     // Collect symbol information.
326     StringRef Name = Decl->getName();
327     StringRef USR = API.recordUSR(Decl);
328     PresumedLoc Loc =
329         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
330     AvailabilityInfo Availability = getAvailability(Decl);
331     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
332     DocComment Comment;
333     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
334       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
335                                               Context.getDiagnostics());
336 
337     // Build declaration fragments, sub-heading, and signature of the function.
338     DeclarationFragments Declaration =
339         DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
340     DeclarationFragments SubHeading =
341         DeclarationFragmentsBuilder::getSubHeading(Decl);
342     FunctionSignature Signature =
343         DeclarationFragmentsBuilder::getFunctionSignature(Decl);
344 
345     // Add the function record to the API set.
346     API.addGlobalFunction(Name, USR, Loc, Availability, Linkage, Comment,
347                           Declaration, SubHeading, Signature);
348     return true;
349   }
350 
351   bool VisitEnumDecl(const EnumDecl *Decl) {
352     if (!Decl->isComplete())
353       return true;
354 
355     // Skip forward declaration.
356     if (!Decl->isThisDeclarationADefinition())
357       return true;
358 
359     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
360       return true;
361 
362     // Collect symbol information.
363     std::string NameString = Decl->getQualifiedNameAsString();
364     StringRef Name(NameString);
365     if (Name.empty())
366       Name = getTypedefName(Decl);
367 
368     StringRef USR = API.recordUSR(Decl);
369     PresumedLoc Loc =
370         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
371     AvailabilityInfo Availability = getAvailability(Decl);
372     DocComment Comment;
373     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
374       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
375                                               Context.getDiagnostics());
376 
377     // Build declaration fragments and sub-heading for the enum.
378     DeclarationFragments Declaration =
379         DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
380     DeclarationFragments SubHeading =
381         DeclarationFragmentsBuilder::getSubHeading(Decl);
382 
383     EnumRecord *EnumRecord =
384         API.addEnum(API.copyString(Name), USR, Loc, Availability, Comment,
385                     Declaration, SubHeading);
386 
387     // Now collect information about the enumerators in this enum.
388     recordEnumConstants(EnumRecord, Decl->enumerators());
389 
390     return true;
391   }
392 
393   bool VisitRecordDecl(const RecordDecl *Decl) {
394     if (!Decl->isCompleteDefinition())
395       return true;
396 
397     // Skip C++ structs/classes/unions
398     // TODO: support C++ records
399     if (isa<CXXRecordDecl>(Decl))
400       return true;
401 
402     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
403       return true;
404 
405     // Collect symbol information.
406     StringRef Name = Decl->getName();
407     if (Name.empty())
408       Name = getTypedefName(Decl);
409     StringRef USR = API.recordUSR(Decl);
410     PresumedLoc Loc =
411         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
412     AvailabilityInfo Availability = getAvailability(Decl);
413     DocComment Comment;
414     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
415       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
416                                               Context.getDiagnostics());
417 
418     // Build declaration fragments and sub-heading for the struct.
419     DeclarationFragments Declaration =
420         DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
421     DeclarationFragments SubHeading =
422         DeclarationFragmentsBuilder::getSubHeading(Decl);
423 
424     StructRecord *StructRecord = API.addStruct(
425         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
426 
427     // Now collect information about the fields in this struct.
428     recordStructFields(StructRecord, Decl->fields());
429 
430     return true;
431   }
432 
433   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
434     // Skip forward declaration for classes (@class)
435     if (!Decl->isThisDeclarationADefinition())
436       return true;
437 
438     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
439       return true;
440 
441     // Collect symbol information.
442     StringRef Name = Decl->getName();
443     StringRef USR = API.recordUSR(Decl);
444     PresumedLoc Loc =
445         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
446     AvailabilityInfo Availability = getAvailability(Decl);
447     LinkageInfo Linkage = Decl->getLinkageAndVisibility();
448     DocComment Comment;
449     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
450       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
451                                               Context.getDiagnostics());
452 
453     // Build declaration fragments and sub-heading for the interface.
454     DeclarationFragments Declaration =
455         DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
456     DeclarationFragments SubHeading =
457         DeclarationFragmentsBuilder::getSubHeading(Decl);
458 
459     // Collect super class information.
460     SymbolReference SuperClass;
461     if (const auto *SuperClassDecl = Decl->getSuperClass()) {
462       SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
463       SuperClass.USR = API.recordUSR(SuperClassDecl);
464     }
465 
466     ObjCInterfaceRecord *ObjCInterfaceRecord =
467         API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
468                              Declaration, SubHeading, SuperClass);
469 
470     // Record all methods (selectors). This doesn't include automatically
471     // synthesized property methods.
472     recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
473     recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
474     recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
475     recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
476 
477     return true;
478   }
479 
480   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
481     // Skip forward declaration for protocols (@protocol).
482     if (!Decl->isThisDeclarationADefinition())
483       return true;
484 
485     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
486       return true;
487 
488     // Collect symbol information.
489     StringRef Name = Decl->getName();
490     StringRef USR = API.recordUSR(Decl);
491     PresumedLoc Loc =
492         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
493     AvailabilityInfo Availability = getAvailability(Decl);
494     DocComment Comment;
495     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
496       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
497                                               Context.getDiagnostics());
498 
499     // Build declaration fragments and sub-heading for the protocol.
500     DeclarationFragments Declaration =
501         DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
502     DeclarationFragments SubHeading =
503         DeclarationFragmentsBuilder::getSubHeading(Decl);
504 
505     ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
506         Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
507 
508     recordObjCMethods(ObjCProtocolRecord, Decl->methods());
509     recordObjCProperties(ObjCProtocolRecord, Decl->properties());
510     recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
511 
512     return true;
513   }
514 
515   bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
516     // Skip ObjC Type Parameter for now.
517     if (isa<ObjCTypeParamDecl>(Decl))
518       return true;
519 
520     if (!Decl->isDefinedOutsideFunctionOrMethod())
521       return true;
522 
523     if (!LCF.isLocationInKnownFile(Decl->getLocation()))
524       return true;
525 
526     PresumedLoc Loc =
527         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
528     StringRef Name = Decl->getName();
529     AvailabilityInfo Availability = getAvailability(Decl);
530     StringRef USR = API.recordUSR(Decl);
531     DocComment Comment;
532     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
533       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
534                                               Context.getDiagnostics());
535 
536     QualType Type = Decl->getUnderlyingType();
537     SymbolReference SymRef =
538         TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
539                                                                          API);
540 
541     API.addTypedef(Name, USR, Loc, Availability, Comment,
542                    DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
543                    DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
544 
545     return true;
546   }
547 
548   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
549     // Collect symbol information.
550     StringRef Name = Decl->getName();
551     StringRef USR = API.recordUSR(Decl);
552     PresumedLoc Loc =
553         Context.getSourceManager().getPresumedLoc(Decl->getLocation());
554     AvailabilityInfo Availability = getAvailability(Decl);
555     DocComment Comment;
556     if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
557       Comment = RawComment->getFormattedLines(Context.getSourceManager(),
558                                               Context.getDiagnostics());
559     // Build declaration fragments and sub-heading for the category.
560     DeclarationFragments Declaration =
561         DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
562     DeclarationFragments SubHeading =
563         DeclarationFragmentsBuilder::getSubHeading(Decl);
564 
565     const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
566     SymbolReference Interface(InterfaceDecl->getName(),
567                               API.recordUSR(InterfaceDecl));
568 
569     ObjCCategoryRecord *ObjCCategoryRecord =
570         API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration,
571                             SubHeading, Interface);
572 
573     recordObjCMethods(ObjCCategoryRecord, Decl->methods());
574     recordObjCProperties(ObjCCategoryRecord, Decl->properties());
575     recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
576     recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
577 
578     return true;
579   }
580 
581 private:
582   /// Get availability information of the declaration \p D.
583   AvailabilityInfo getAvailability(const Decl *D) const {
584     StringRef PlatformName = Context.getTargetInfo().getPlatformName();
585 
586     AvailabilityInfo Availability;
587     // Collect availability attributes from all redeclarations.
588     for (const auto *RD : D->redecls()) {
589       for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
590         if (A->getPlatform()->getName() != PlatformName)
591           continue;
592         Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
593                                         A->getObsoleted(), A->getUnavailable(),
594                                         /* UnconditionallyDeprecated */ false,
595                                         /* UnconditionallyUnavailable */ false);
596         break;
597       }
598 
599       if (const auto *A = RD->getAttr<UnavailableAttr>())
600         if (!A->isImplicit()) {
601           Availability.Unavailable = true;
602           Availability.UnconditionallyUnavailable = true;
603         }
604 
605       if (const auto *A = RD->getAttr<DeprecatedAttr>())
606         if (!A->isImplicit())
607           Availability.UnconditionallyDeprecated = true;
608     }
609 
610     return Availability;
611   }
612 
613   /// Collect API information for the enum constants and associate with the
614   /// parent enum.
615   void recordEnumConstants(EnumRecord *EnumRecord,
616                            const EnumDecl::enumerator_range Constants) {
617     for (const auto *Constant : Constants) {
618       // Collect symbol information.
619       StringRef Name = Constant->getName();
620       StringRef USR = API.recordUSR(Constant);
621       PresumedLoc Loc =
622           Context.getSourceManager().getPresumedLoc(Constant->getLocation());
623       AvailabilityInfo Availability = getAvailability(Constant);
624       DocComment Comment;
625       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
626         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
627                                                 Context.getDiagnostics());
628 
629       // Build declaration fragments and sub-heading for the enum constant.
630       DeclarationFragments Declaration =
631           DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
632       DeclarationFragments SubHeading =
633           DeclarationFragmentsBuilder::getSubHeading(Constant);
634 
635       API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
636                           Declaration, SubHeading);
637     }
638   }
639 
640   /// Collect API information for the struct fields and associate with the
641   /// parent struct.
642   void recordStructFields(StructRecord *StructRecord,
643                           const RecordDecl::field_range Fields) {
644     for (const auto *Field : Fields) {
645       // Collect symbol information.
646       StringRef Name = Field->getName();
647       StringRef USR = API.recordUSR(Field);
648       PresumedLoc Loc =
649           Context.getSourceManager().getPresumedLoc(Field->getLocation());
650       AvailabilityInfo Availability = getAvailability(Field);
651       DocComment Comment;
652       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
653         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
654                                                 Context.getDiagnostics());
655 
656       // Build declaration fragments and sub-heading for the struct field.
657       DeclarationFragments Declaration =
658           DeclarationFragmentsBuilder::getFragmentsForField(Field);
659       DeclarationFragments SubHeading =
660           DeclarationFragmentsBuilder::getSubHeading(Field);
661 
662       API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
663                          Declaration, SubHeading);
664     }
665   }
666 
667   /// Collect API information for the Objective-C methods and associate with the
668   /// parent container.
669   void recordObjCMethods(ObjCContainerRecord *Container,
670                          const ObjCContainerDecl::method_range Methods) {
671     for (const auto *Method : Methods) {
672       // Don't record selectors for properties.
673       if (Method->isPropertyAccessor())
674         continue;
675 
676       StringRef Name = API.copyString(Method->getSelector().getAsString());
677       StringRef USR = API.recordUSR(Method);
678       PresumedLoc Loc =
679           Context.getSourceManager().getPresumedLoc(Method->getLocation());
680       AvailabilityInfo Availability = getAvailability(Method);
681       DocComment Comment;
682       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
683         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
684                                                 Context.getDiagnostics());
685 
686       // Build declaration fragments, sub-heading, and signature for the method.
687       DeclarationFragments Declaration =
688           DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
689       DeclarationFragments SubHeading =
690           DeclarationFragmentsBuilder::getSubHeading(Method);
691       FunctionSignature Signature =
692           DeclarationFragmentsBuilder::getFunctionSignature(Method);
693 
694       API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
695                         Declaration, SubHeading, Signature,
696                         Method->isInstanceMethod());
697     }
698   }
699 
700   void recordObjCProperties(ObjCContainerRecord *Container,
701                             const ObjCContainerDecl::prop_range Properties) {
702     for (const auto *Property : Properties) {
703       StringRef Name = Property->getName();
704       StringRef USR = API.recordUSR(Property);
705       PresumedLoc Loc =
706           Context.getSourceManager().getPresumedLoc(Property->getLocation());
707       AvailabilityInfo Availability = getAvailability(Property);
708       DocComment Comment;
709       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
710         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
711                                                 Context.getDiagnostics());
712 
713       // Build declaration fragments and sub-heading for the property.
714       DeclarationFragments Declaration =
715           DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
716       DeclarationFragments SubHeading =
717           DeclarationFragmentsBuilder::getSubHeading(Property);
718 
719       StringRef GetterName =
720           API.copyString(Property->getGetterName().getAsString());
721       StringRef SetterName =
722           API.copyString(Property->getSetterName().getAsString());
723 
724       // Get the attributes for property.
725       unsigned Attributes = ObjCPropertyRecord::NoAttr;
726       if (Property->getPropertyAttributes() &
727           ObjCPropertyAttribute::kind_readonly)
728         Attributes |= ObjCPropertyRecord::ReadOnly;
729       if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
730         Attributes |= ObjCPropertyRecord::Class;
731 
732       API.addObjCProperty(
733           Container, Name, USR, Loc, Availability, Comment, Declaration,
734           SubHeading,
735           static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
736           GetterName, SetterName, Property->isOptional());
737     }
738   }
739 
740   void recordObjCInstanceVariables(
741       ObjCContainerRecord *Container,
742       const llvm::iterator_range<
743           DeclContext::specific_decl_iterator<ObjCIvarDecl>>
744           Ivars) {
745     for (const auto *Ivar : Ivars) {
746       StringRef Name = Ivar->getName();
747       StringRef USR = API.recordUSR(Ivar);
748       PresumedLoc Loc =
749           Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
750       AvailabilityInfo Availability = getAvailability(Ivar);
751       DocComment Comment;
752       if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
753         Comment = RawComment->getFormattedLines(Context.getSourceManager(),
754                                                 Context.getDiagnostics());
755 
756       // Build declaration fragments and sub-heading for the instance variable.
757       DeclarationFragments Declaration =
758           DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
759       DeclarationFragments SubHeading =
760           DeclarationFragmentsBuilder::getSubHeading(Ivar);
761 
762       ObjCInstanceVariableRecord::AccessControl Access =
763           Ivar->getCanonicalAccessControl();
764 
765       API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
766                                   Comment, Declaration, SubHeading, Access);
767     }
768   }
769 
770   void recordObjCProtocols(ObjCContainerRecord *Container,
771                            ObjCInterfaceDecl::protocol_range Protocols) {
772     for (const auto *Protocol : Protocols)
773       Container->Protocols.emplace_back(Protocol->getName(),
774                                         API.recordUSR(Protocol));
775   }
776 
777   ASTContext &Context;
778   APISet &API;
779   LocationFileChecker &LCF;
780 };
781 
782 class ExtractAPIConsumer : public ASTConsumer {
783 public:
784   ExtractAPIConsumer(ASTContext &Context,
785                      std::unique_ptr<LocationFileChecker> LCF, APISet &API)
786       : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {}
787 
788   void HandleTranslationUnit(ASTContext &Context) override {
789     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
790     Visitor.TraverseDecl(Context.getTranslationUnitDecl());
791   }
792 
793 private:
794   ExtractAPIVisitor Visitor;
795   std::unique_ptr<LocationFileChecker> LCF;
796 };
797 
798 class MacroCallback : public PPCallbacks {
799 public:
800   MacroCallback(const SourceManager &SM, LocationFileChecker &LCF, APISet &API,
801                 Preprocessor &PP)
802       : SM(SM), LCF(LCF), API(API), PP(PP) {}
803 
804   void MacroDefined(const Token &MacroNameToken,
805                     const MacroDirective *MD) override {
806     auto *MacroInfo = MD->getMacroInfo();
807 
808     if (MacroInfo->isBuiltinMacro())
809       return;
810 
811     auto SourceLoc = MacroNameToken.getLocation();
812     if (SM.isWrittenInBuiltinFile(SourceLoc) ||
813         SM.isWrittenInCommandLineFile(SourceLoc))
814       return;
815 
816     PendingMacros.emplace_back(MacroNameToken, MD);
817   }
818 
819   // If a macro gets undefined at some point during preprocessing of the inputs
820   // it means that it isn't an exposed API and we should therefore not add a
821   // macro definition for it.
822   void MacroUndefined(const Token &MacroNameToken, const MacroDefinition &MD,
823                       const MacroDirective *Undef) override {
824     // If this macro wasn't previously defined we don't need to do anything
825     // here.
826     if (!Undef)
827       return;
828 
829     llvm::erase_if(PendingMacros, [&MD, this](const PendingMacro &PM) {
830       return MD.getMacroInfo()->isIdenticalTo(*PM.MD->getMacroInfo(), PP,
831                                               /*Syntactically*/ false);
832     });
833   }
834 
835   void EndOfMainFile() override {
836     for (auto &PM : PendingMacros) {
837       // `isUsedForHeaderGuard` is only set when the preprocessor leaves the
838       // file so check for it here.
839       if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
840         continue;
841 
842       if (!LCF.isLocationInKnownFile(PM.MacroNameToken.getLocation()))
843         continue;
844 
845       StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
846       PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation());
847       StringRef USR =
848           API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM);
849 
850       API.addMacroDefinition(
851           Name, USR, Loc,
852           DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
853           DeclarationFragmentsBuilder::getSubHeadingForMacro(Name));
854     }
855 
856     PendingMacros.clear();
857   }
858 
859 private:
860   struct PendingMacro {
861     Token MacroNameToken;
862     const MacroDirective *MD;
863 
864     PendingMacro(const Token &MacroNameToken, const MacroDirective *MD)
865         : MacroNameToken(MacroNameToken), MD(MD) {}
866   };
867 
868   const SourceManager &SM;
869   LocationFileChecker &LCF;
870   APISet &API;
871   Preprocessor &PP;
872   llvm::SmallVector<PendingMacro> PendingMacros;
873 };
874 
875 } // namespace
876 
877 std::unique_ptr<ASTConsumer>
878 ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
879   OS = CreateOutputFile(CI, InFile);
880   if (!OS)
881     return nullptr;
882 
883   ProductName = CI.getFrontendOpts().ProductName;
884 
885   // Now that we have enough information about the language options and the
886   // target triple, let's create the APISet before anyone uses it.
887   API = std::make_unique<APISet>(
888       CI.getTarget().getTriple(),
889       CI.getFrontendOpts().Inputs.back().getKind().getLanguage());
890 
891   auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
892 
893   CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
894       CI.getSourceManager(), *LCF, *API, CI.getPreprocessor()));
895 
896   return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
897                                               std::move(LCF), *API);
898 }
899 
900 bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
901   auto &Inputs = CI.getFrontendOpts().Inputs;
902   if (Inputs.empty())
903     return true;
904 
905   if (!CI.hasFileManager())
906     if (!CI.createFileManager())
907       return false;
908 
909   auto Kind = Inputs[0].getKind();
910 
911   // Convert the header file inputs into a single input buffer.
912   SmallString<256> HeaderContents;
913   bool IsQuoted = false;
914   for (const FrontendInputFile &FIF : Inputs) {
915     if (Kind.isObjectiveC())
916       HeaderContents += "#import";
917     else
918       HeaderContents += "#include";
919 
920     StringRef FilePath = FIF.getFile();
921     if (auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
922       if (IsQuoted)
923         HeaderContents += " \"";
924       else
925         HeaderContents += " <";
926 
927       HeaderContents += *RelativeName;
928 
929       if (IsQuoted)
930         HeaderContents += "\"\n";
931       else
932         HeaderContents += ">\n";
933       KnownInputFiles.emplace_back(*RelativeName, IsQuoted);
934     } else {
935       HeaderContents += " \"";
936       HeaderContents += FilePath;
937       HeaderContents += "\"\n";
938       KnownInputFiles.emplace_back(FilePath, true);
939     }
940   }
941 
942   if (CI.getHeaderSearchOpts().Verbose)
943     CI.getVerboseOutputStream() << getInputBufferName() << ":\n"
944                                 << HeaderContents << "\n";
945 
946   Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
947                                                 getInputBufferName());
948 
949   // Set that buffer up as our "real" input in the CompilerInstance.
950   Inputs.clear();
951   Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
952 
953   return true;
954 }
955 
956 void ExtractAPIAction::EndSourceFileAction() {
957   if (!OS)
958     return;
959 
960   // Setup a SymbolGraphSerializer to write out collected API information in
961   // the Symbol Graph format.
962   // FIXME: Make the kind of APISerializer configurable.
963   SymbolGraphSerializer SGSerializer(*API, ProductName);
964   SGSerializer.serialize(*OS);
965   OS.reset();
966 }
967 
968 std::unique_ptr<raw_pwrite_stream>
969 ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) {
970   std::unique_ptr<raw_pwrite_stream> OS =
971       CI.createDefaultOutputFile(/*Binary=*/false, InFile, /*Extension=*/"json",
972                                  /*RemoveFileOnSignal=*/false);
973   if (!OS)
974     return nullptr;
975   return OS;
976 }
977