clang 23.0.0git
ExtractAPIConsumer.cpp
Go to the documentation of this file.
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 ASTConsumer to collect API
11/// information.
12///
13//===----------------------------------------------------------------------===//
14
18#include "clang/AST/DeclObjC.h"
34#include "clang/Lex/MacroInfo.h"
39#include "llvm/ADT/DenseSet.h"
40#include "llvm/ADT/STLExtras.h"
41#include "llvm/ADT/SmallString.h"
42#include "llvm/ADT/SmallVector.h"
43#include "llvm/ADT/StringRef.h"
44#include "llvm/Support/Casting.h"
45#include "llvm/Support/Error.h"
46#include "llvm/Support/MemoryBuffer.h"
47#include "llvm/Support/Path.h"
48#include "llvm/Support/Regex.h"
49#include "llvm/Support/raw_ostream.h"
50#include <memory>
51#include <optional>
52#include <utility>
53
54using namespace clang;
55using namespace extractapi;
56
57namespace {
58
59std::optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
60 StringRef File,
61 bool *IsQuoted = nullptr) {
62 assert(CI.hasFileManager() &&
63 "CompilerInstance does not have a FileManager!");
64
65 using namespace llvm::sys;
66 const auto &FS = CI.getVirtualFileSystem();
67
68 SmallString<128> FilePath(File.begin(), File.end());
69 FS.makeAbsolute(FilePath);
70 path::remove_dots(FilePath, true);
71 FilePath = path::convert_to_slash(FilePath);
72 File = FilePath;
73
74 // Checks whether `Dir` is a strict path prefix of `File`. If so returns
75 // the prefix length. Otherwise return 0.
76 auto CheckDir = [&](llvm::StringRef Dir) -> unsigned {
77 llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
78 FS.makeAbsolute(DirPath);
79 path::remove_dots(DirPath, true);
80 Dir = DirPath;
81 for (auto NI = path::begin(File), NE = path::end(File),
82 DI = path::begin(Dir), DE = path::end(Dir);
83 /*termination condition in loop*/; ++NI, ++DI) {
84 // '.' components in File are ignored.
85 while (NI != NE && *NI == ".")
86 ++NI;
87 if (NI == NE)
88 break;
89
90 // '.' components in Dir are ignored.
91 while (DI != DE && *DI == ".")
92 ++DI;
93
94 // Dir is a prefix of File, up to '.' components and choice of path
95 // separators.
96 if (DI == DE)
97 return NI - path::begin(File);
98
99 // Consider all path separators equal.
100 if (NI->size() == 1 && DI->size() == 1 &&
101 path::is_separator(NI->front()) && path::is_separator(DI->front()))
102 continue;
103
104 // Special case Apple .sdk folders since the search path is typically a
105 // symlink like `iPhoneSimulator14.5.sdk` while the file is instead
106 // located in `iPhoneSimulator.sdk` (the real folder).
107 if (NI->ends_with(".sdk") && DI->ends_with(".sdk")) {
108 StringRef NBasename = path::stem(*NI);
109 StringRef DBasename = path::stem(*DI);
110 if (DBasename.starts_with(NBasename))
111 continue;
112 }
113
114 if (*NI != *DI)
115 break;
116 }
117 return 0;
118 };
119
120 unsigned PrefixLength = 0;
121
122 // Go through the search paths and find the first one that is a prefix of
123 // the header.
124 for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries) {
125 // Note whether the match is found in a quoted entry.
126 if (IsQuoted)
127 *IsQuoted = Entry.Group == frontend::Quoted;
128
129 if (auto EntryFile = CI.getFileManager().getOptionalFileRef(Entry.Path)) {
130 if (auto HMap = HeaderMap::Create(*EntryFile, CI.getFileManager())) {
131 // If this is a headermap entry, try to reverse lookup the full path
132 // for a spelled name before mapping.
133 StringRef SpelledFilename = HMap->reverseLookupFilename(File);
134 if (!SpelledFilename.empty())
135 return SpelledFilename.str();
136
137 // No matching mapping in this headermap, try next search entry.
138 continue;
139 }
140 }
141
142 // Entry is a directory search entry, try to check if it's a prefix of File.
143 PrefixLength = CheckDir(Entry.Path);
144 if (PrefixLength > 0) {
145 // The header is found in a framework path, construct the framework-style
146 // include name `<Framework/Header.h>`
147 if (Entry.IsFramework) {
150 File, &Matches);
151 // Returned matches are always in stable order.
152 if (Matches.size() != 4)
153 return std::nullopt;
154
155 return path::convert_to_slash(
156 (Matches[1].drop_front(Matches[1].rfind('/') + 1) + "/" +
157 Matches[3])
158 .str());
159 }
160
161 // The header is found in a normal search path, strip the search path
162 // prefix to get an include name.
163 return path::convert_to_slash(File.drop_front(PrefixLength));
164 }
165 }
166
167 // Couldn't determine a include name, use full path instead.
168 return std::nullopt;
169}
170
171std::optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
172 FileEntryRef FE,
173 bool *IsQuoted = nullptr) {
174 return getRelativeIncludeName(CI, FE.getNameAsRequested(), IsQuoted);
175}
176
177struct LocationFileChecker {
178 bool operator()(SourceLocation Loc) {
179 // If the loc refers to a macro expansion we need to first get the file
180 // location of the expansion.
181 auto &SM = CI.getSourceManager();
182 auto FileLoc = SM.getFileLoc(Loc);
183 FileID FID = SM.getFileID(FileLoc);
184 if (FID.isInvalid())
185 return false;
186
187 OptionalFileEntryRef File = SM.getFileEntryRefForID(FID);
188 if (!File)
189 return false;
190
191 if (KnownFileEntries.count(*File))
192 return true;
193
194 if (ExternalFileEntries.count(*File))
195 return false;
196
197 // Try to reduce the include name the same way we tried to include it.
198 bool IsQuoted = false;
199 if (auto IncludeName = getRelativeIncludeName(CI, *File, &IsQuoted))
200 if (llvm::any_of(KnownFiles,
201 [&IsQuoted, &IncludeName](const auto &KnownFile) {
202 return KnownFile.first.equals(*IncludeName) &&
203 KnownFile.second == IsQuoted;
204 })) {
205 KnownFileEntries.insert(*File);
206 return true;
207 }
208
209 // Record that the file was not found to avoid future reverse lookup for
210 // the same file.
211 ExternalFileEntries.insert(*File);
212 return false;
213 }
214
215 LocationFileChecker(const CompilerInstance &CI,
216 SmallVector<std::pair<SmallString<32>, bool>> &KnownFiles)
217 : CI(CI), KnownFiles(KnownFiles), ExternalFileEntries() {
218 for (const auto &KnownFile : KnownFiles)
219 if (auto FE = CI.getFileManager().getOptionalFileRef(KnownFile.first))
220 KnownFileEntries.insert(*FE);
221 }
222
223private:
224 const CompilerInstance &CI;
225 SmallVector<std::pair<SmallString<32>, bool>> &KnownFiles;
226 llvm::DenseSet<const FileEntry *> KnownFileEntries;
227 llvm::DenseSet<const FileEntry *> ExternalFileEntries;
228};
229
230struct BatchExtractAPIVisitor : ExtractAPIVisitor<BatchExtractAPIVisitor> {
231 bool shouldDeclBeIncluded(const Decl *D) const {
232 bool ShouldBeIncluded = true;
233 // Check that we have the definition for redeclarable types.
234 if (auto *TD = llvm::dyn_cast<TagDecl>(D))
235 ShouldBeIncluded = TD->isThisDeclarationADefinition();
236 else if (auto *Interface = llvm::dyn_cast<ObjCInterfaceDecl>(D))
237 ShouldBeIncluded = Interface->isThisDeclarationADefinition();
238 else if (auto *Protocol = llvm::dyn_cast<ObjCProtocolDecl>(D))
239 ShouldBeIncluded = Protocol->isThisDeclarationADefinition();
240
241 ShouldBeIncluded = ShouldBeIncluded && LCF(D->getLocation());
242 return ShouldBeIncluded;
243 }
244
245 BatchExtractAPIVisitor(LocationFileChecker &LCF, ASTContext &Context,
246 APISet &API)
247 : ExtractAPIVisitor<BatchExtractAPIVisitor>(Context, API), LCF(LCF) {}
248
249private:
250 LocationFileChecker &LCF;
251};
252
253class WrappingExtractAPIConsumer : public ASTConsumer {
254public:
255 WrappingExtractAPIConsumer(ASTContext &Context, APISet &API)
256 : Visitor(Context, API) {}
257
258 void HandleTranslationUnit(ASTContext &Context) override {
259 // Use ExtractAPIVisitor to traverse symbol declarations in the context.
260 Visitor.TraverseDecl(Context.getTranslationUnitDecl());
261 }
262
263private:
264 ExtractAPIVisitor<> Visitor;
265};
266
267class ExtractAPIConsumer : public ASTConsumer {
268public:
269 ExtractAPIConsumer(ASTContext &Context,
270 std::unique_ptr<LocationFileChecker> LCF, APISet &API)
271 : Visitor(*LCF, Context, API), LCF(std::move(LCF)) {}
272
273 void HandleTranslationUnit(ASTContext &Context) override {
274 // Use ExtractAPIVisitor to traverse symbol declarations in the context.
275 Visitor.TraverseDecl(Context.getTranslationUnitDecl());
276 }
277
278private:
279 BatchExtractAPIVisitor Visitor;
280 std::unique_ptr<LocationFileChecker> LCF;
281};
282
283class MacroCallback : public PPCallbacks {
284public:
285 MacroCallback(ASTContext &Ctx, const SourceManager &SM, APISet &API,
286 Preprocessor &PP)
287 : Ctx(Ctx), SM(SM), API(API), PP(PP) {}
288
289 void EndOfMainFile() override {
290 for (const auto &M : PP.macros()) {
291 auto *II = M.getFirst();
292 auto MD = PP.getMacroDefinition(II);
293 auto *MI = MD.getMacroInfo();
294
295 if (!MI)
296 continue;
297
298 // Ignore header guard macros
299 if (MI->isUsedForHeaderGuard())
300 continue;
301
302 // Ignore builtin macros and ones defined via the command line.
303 if (MI->isBuiltinMacro())
304 continue;
305
306 auto DefLoc = MI->getDefinitionLoc();
307
308 if (SM.isInPredefinedFile(DefLoc))
309 continue;
310
311 auto AssociatedModuleMacros = MD.getModuleMacros();
312 StringRef OwningModuleName;
313 if (!AssociatedModuleMacros.empty())
314 OwningModuleName = AssociatedModuleMacros.back()
315 ->getOwningModule()
316 ->getTopLevelModuleName();
317
318 if (!shouldMacroBeIncluded(DefLoc, OwningModuleName))
319 continue;
320
321 StringRef Name = II->getName();
322 PresumedLoc Loc = SM.getPresumedLoc(DefLoc);
323 SmallString<128> USR;
324 index::generateUSRForMacro(Name, DefLoc, SM, USR);
325
326 DocComment Comment;
327 if (const auto *RC = Ctx.getRawCommentForAnyRedecl(MI))
328 Comment = RC->getFormattedLines(SM, Ctx.getDiagnostics());
329
330 API.createRecord<extractapi::MacroDefinitionRecord>(
331 USR, Name, SymbolReference(), Loc, Comment,
334 SM.isInSystemHeader(DefLoc));
335 }
336 }
337
338 virtual bool shouldMacroBeIncluded(const SourceLocation &MacroLoc,
339 StringRef ModuleName) {
340 return true;
341 }
342
343 ASTContext &Ctx;
344 const SourceManager &SM;
345 APISet &API;
346 Preprocessor &PP;
347};
348
349class APIMacroCallback : public MacroCallback {
350public:
351 APIMacroCallback(ASTContext &Ctx, const SourceManager &SM, APISet &API,
352 Preprocessor &PP, LocationFileChecker &LCF)
353 : MacroCallback(Ctx, SM, API, PP), LCF(LCF) {}
354
355 bool shouldMacroBeIncluded(const SourceLocation &MacroLoc,
356 StringRef ModuleName) override {
357 // Do not include macros from external files
358 return LCF(MacroLoc);
359 }
360
361private:
362 LocationFileChecker &LCF;
363};
364
365std::unique_ptr<llvm::raw_pwrite_stream>
366createAdditionalSymbolGraphFile(CompilerInstance &CI, Twine BaseName) {
367 auto OutputDirectory = CI.getFrontendOpts().SymbolGraphOutputDir;
368
370 llvm::sys::path::append(FileName, OutputDirectory,
371 BaseName + ".symbols.json");
372 return CI.createOutputFile(
373 FileName, /*Binary*/ false, /*RemoveFileOnSignal*/ false,
374 /*UseTemporary*/ true, /*CreateMissingDirectories*/ true);
375}
376
377} // namespace
378
380 SymbolGraphSerializerOption SerializationOptions;
381 SerializationOptions.Compact = !CI.getFrontendOpts().EmitPrettySymbolGraphs;
382 SerializationOptions.EmitSymbolLabelsForTesting =
384
386 auto ConstructOutputFile = [&CI](Twine BaseName) {
387 return createAdditionalSymbolGraphFile(CI, BaseName);
388 };
389
391 *OS, *API, IgnoresList, ConstructOutputFile, SerializationOptions);
392 } else {
394 SerializationOptions);
395 }
396
397 // Flush the stream and close the main output stream.
398 OS.reset();
399}
400
401std::unique_ptr<ASTConsumer>
404
405 if (CI.getFrontendOpts().SymbolGraphOutputDir.empty())
406 OS = CI.createDefaultOutputFile(/*Binary*/ false, InFile,
407 /*Extension*/ "symbols.json",
408 /*RemoveFileOnSignal*/ false,
409 /*CreateMissingDirectories*/ true);
410 else
411 OS = createAdditionalSymbolGraphFile(CI, ProductName);
412
413 if (!OS)
414 return nullptr;
415
416 // Now that we have enough information about the language options and the
417 // target triple, let's create the APISet before anyone uses it.
418 API = std::make_unique<APISet>(
419 CI.getTarget().getTriple(),
420 CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), ProductName);
421
422 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
423
424 CI.getPreprocessor().addPPCallbacks(std::make_unique<APIMacroCallback>(
426 *LCF));
427
428 // Do not include location in anonymous decls.
430 Policy.AnonymousTagNameStyle =
431 llvm::to_underlying(PrintingPolicy::AnonymousTagMode::Plain);
432 CI.getASTContext().setPrintingPolicy(Policy);
433
434 if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
435 llvm::handleAllErrors(
437 CI.getFileManager())
438 .moveInto(IgnoresList),
439 [&CI](const IgnoresFileNotFound &Err) {
440 CI.getDiagnostics().Report(
441 diag::err_extract_api_ignores_file_not_found)
442 << Err.Path;
443 });
444 }
445
446 return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
447 std::move(LCF), *API);
448}
449
450bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
451 auto &Inputs = CI.getFrontendOpts().Inputs;
452 if (Inputs.empty())
453 return true;
454
455 if (!CI.hasFileManager())
457
458 auto Kind = Inputs[0].getKind();
459
460 // Convert the header file inputs into a single input buffer.
461 SmallString<256> HeaderContents;
462 bool IsQuoted = false;
463 for (const FrontendInputFile &FIF : Inputs) {
464 if (Kind.isObjectiveC())
465 HeaderContents += "#import";
466 else
467 HeaderContents += "#include";
468
469 StringRef FilePath = FIF.getFile();
470 if (auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
471 if (IsQuoted)
472 HeaderContents += " \"";
473 else
474 HeaderContents += " <";
475
476 HeaderContents += *RelativeName;
477
478 if (IsQuoted)
479 HeaderContents += "\"\n";
480 else
481 HeaderContents += ">\n";
482 KnownInputFiles.emplace_back(static_cast<SmallString<32>>(*RelativeName),
483 IsQuoted);
484 } else {
485 HeaderContents += " \"";
486 HeaderContents += FilePath;
487 HeaderContents += "\"\n";
488 KnownInputFiles.emplace_back(FilePath, true);
489 }
490 }
491
493 CI.getVerboseOutputStream() << getInputBufferName() << ":\n"
494 << HeaderContents << "\n";
495
496 Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
497 getInputBufferName());
498
499 // Set that buffer up as our "real" input in the CompilerInstance.
500 Inputs.clear();
501 Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
502
503 return true;
504}
505
508}
509
510std::unique_ptr<ASTConsumer>
512 StringRef InFile) {
513 auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
514 if (!OtherConsumer)
515 return nullptr;
516
517 CreatedASTConsumer = true;
518
520 auto InputFilename = llvm::sys::path::filename(InFile);
521 OS = createAdditionalSymbolGraphFile(CI, InputFilename);
522
523 // Now that we have enough information about the language options and the
524 // target triple, let's create the APISet before anyone uses it.
525 API = std::make_unique<APISet>(
526 CI.getTarget().getTriple(),
527 CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), ProductName);
528
529 CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
531
532 // Do not include location in anonymous decls.
534 Policy.AnonymousTagNameStyle =
535 llvm::to_underlying(PrintingPolicy::AnonymousTagMode::Plain);
536 CI.getASTContext().setPrintingPolicy(Policy);
537
538 if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
539 llvm::handleAllErrors(
541 CI.getFileManager())
542 .moveInto(IgnoresList),
543 [&CI](const IgnoresFileNotFound &Err) {
544 CI.getDiagnostics().Report(
545 diag::err_extract_api_ignores_file_not_found)
546 << Err.Path;
547 });
548 }
549
550 auto WrappingConsumer =
551 std::make_unique<WrappingExtractAPIConsumer>(CI.getASTContext(), *API);
552 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
553 Consumers.push_back(std::move(OtherConsumer));
554 Consumers.push_back(std::move(WrappingConsumer));
555
556 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
557}
558
560 // Invoke wrapped action's method.
562
563 if (CreatedASTConsumer) {
565 }
566}
This file defines the APIRecord-based structs and the APISet class.
This file provides AST data structures related to concepts.
Defines the clang::ASTContext interface.
This file defines the ExtractAPVisitor AST visitation interface.
This file defines the ExtractAPIAction and WrappingExtractAPIAction frontend actions.
Defines interfaces for clang::FileEntry and clang::FileEntryRef.
Defines the clang::MacroInfo and clang::MacroDirective classes.
#define SM(sm)
Defines the PPCallbacks interface.
Defines the clang::Preprocessor interface.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
This file defines the SymbolGraphSerializer class.
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition ASTConsumer.h:35
TranslationUnitDecl * getTranslationUnitDecl() const
const clang::PrintingPolicy & getPrintingPolicy() const
Definition ASTContext.h:860
void setPrintingPolicy(const clang::PrintingPolicy &Policy)
Definition ASTContext.h:864
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
std::unique_ptr< raw_pwrite_stream > createDefaultOutputFile(bool Binary=true, StringRef BaseInput="", StringRef Extension="", bool RemoveFileOnSignal=true, bool CreateMissingDirectories=false, bool ForceUseTemporary=false, bool SetOnlyIfDifferent=false)
Create the default output file (from the invocation's options) and add it to the list of tracked outp...
raw_ostream & getVerboseOutputStream()
Get the current stream for verbose output.
void createFileManager()
Create the file manager and replace any existing one with it.
FileManager & getFileManager() const
Return the current file manager to the caller.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
ASTContext & getASTContext() const
FrontendOptions & getFrontendOpts()
std::unique_ptr< raw_pwrite_stream > createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal, bool UseTemporary, bool CreateMissingDirectories=false, bool SetOnlyIfDifferent=false)
Create a new output file, optionally deriving the output path name, and add it to the list of tracked...
HeaderSearchOptions & getHeaderSearchOpts()
TargetInfo & getTarget() const
llvm::vfs::FileSystem & getVirtualFileSystem() const
SourceManager & getSourceManager() const
Return the current source manager.
SourceLocation getLocation() const
Definition DeclBase.h:447
std::string ProductName
The product this action is extracting API information for.
std::unique_ptr< llvm::MemoryBuffer > Buffer
The synthesized input buffer that contains all the provided input header files.
extractapi::APIIgnoresList IgnoresList
The list of symbols to ignore during serialization.
std::unique_ptr< llvm::raw_pwrite_stream > OS
A stream to the main output file of this action.
std::unique_ptr< extractapi::APISet > API
A representation of the APIs this action extracts.
void ImplEndSourceFileAction(CompilerInstance &CI)
Implements EndSourceFileAction for Symbol-Graph generation.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition FileEntry.h:57
StringRef getNameAsRequested() const
The name of this FileEntry, as originally requested without applying any remappings for VFS 'use-exte...
Definition FileEntry.h:68
bool isInvalid() const
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true, bool IsText=true)
Get a FileEntryRef if it exists, without doing anything on error.
virtual void EndSourceFileAction()
Callback at the end of processing a single input.
CompilerInstance & getCompilerInstance() const
An input file for the front end.
unsigned EmitSymbolGraphSymbolLabelsForTesting
Whether to emit symbol labels for testing in generated symbol graphs.
std::string ProductName
The name of the product the input files belong too.
unsigned EmitExtensionSymbolGraphs
Whether to emit additional symbol graphs for extended modules.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
unsigned EmitPrettySymbolGraphs
Whether to emit symbol labels for testing in generated symbol graphs.
std::vector< std::string > ExtractAPIIgnoresFileList
static std::unique_ptr< HeaderMap > Create(FileEntryRef FE, FileManager &FM)
This attempts to load the specified file as a header map.
Definition HeaderMap.cpp:48
unsigned Verbose
Whether header search information should be output as for -v.
std::vector< Entry > UserEntries
User specified include entries.
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
void EndSourceFileAction() override
Callback at the end of processing a single input.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create ExtractAPI consumer multiplexed on another consumer.
static DeclarationFragments getFragmentsForMacro(StringRef Name, const MacroInfo *MI)
Build DeclarationFragments for a macro.
static DeclarationFragments getSubHeadingForMacro(StringRef Name)
Build a sub-heading for macro Name.
The RecursiveASTVisitor to traverse symbol declarations and collect API information.
static void serializeWithExtensionGraphs(raw_ostream &MainOutput, const APISet &API, const APIIgnoresList &IgnoresList, llvm::function_ref< std::unique_ptr< llvm::raw_pwrite_stream >(llvm::Twine BaseFileName)> CreateOutputStream, SymbolGraphSerializerOption Options={})
static void serializeMainSymbolGraph(raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, SymbolGraphSerializerOption Options={})
static llvm::Regex getFrameworkIncludeRule()
Defines the clang::TargetInfo interface.
std::vector< RawComment::CommentLine > DocComment
DocComment is a vector of RawComment::CommentLine.
Definition API.h:151
@ Quoted
'#include ""' paths, added by 'gcc -iquote'.
bool generateUSRForMacro(const MacroDefinitionRecord *MD, const SourceManager &SM, SmallVectorImpl< char > &Buf)
Generate a USR for a macro, including the USR prefix.
The JSON file list parser is used to communicate input to InstallAPI.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:208
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
Definition TypeBase.h:5973
Describes how types, statements, expressions, and declarations should be printed.
@ Plain
E.g., (anonymous enum)/(unnamed struct)/etc.
static llvm::Expected< APIIgnoresList > create(const FilePathList &IgnoresFilePathList, FileManager &FM)
The API to use for generating from the files at IgnoresFilePathList.
Common options to customize the visitor output.
bool Compact
Do not include unnecessary whitespaces to save space.