clang 24.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 SmallVector<const IdentifierInfo *> Macros;
291 for (const auto &M : PP.macros())
292 Macros.push_back(M.getFirst());
293 llvm::sort(Macros,
294 [](const IdentifierInfo *LHS, const IdentifierInfo *RHS) {
295 return LHS->getName() < RHS->getName();
296 });
297
298 for (const auto *II : Macros) {
299 auto MD = PP.getMacroDefinition(II);
300 auto *MI = MD.getMacroInfo();
301
302 if (!MI)
303 continue;
304
305 // Ignore header guard macros
306 if (MI->isUsedForHeaderGuard())
307 continue;
308
309 // Ignore builtin macros and ones defined via the command line.
310 if (MI->isBuiltinMacro())
311 continue;
312
313 auto DefLoc = MI->getDefinitionLoc();
314
315 if (SM.isInPredefinedFile(DefLoc))
316 continue;
317
318 auto AssociatedModuleMacros = MD.getModuleMacros();
319 StringRef OwningModuleName;
320 if (!AssociatedModuleMacros.empty())
321 OwningModuleName = AssociatedModuleMacros.back()
322 ->getOwningModule()
323 ->getTopLevelModuleName();
324
325 if (!shouldMacroBeIncluded(DefLoc, OwningModuleName))
326 continue;
327
328 StringRef Name = II->getName();
329 PresumedLoc Loc = SM.getPresumedLoc(DefLoc);
330 SmallString<128> USR;
331 index::generateUSRForMacro(Name, DefLoc, SM, USR);
332
333 DocComment Comment;
334 if (const auto *RC = Ctx.getRawCommentForAnyRedecl(MI))
335 Comment = RC->getFormattedLines(SM, Ctx.getDiagnostics());
336
337 API.createRecord<extractapi::MacroDefinitionRecord>(
338 USR, Name, SymbolReference(), Loc, Comment,
341 SM.isInSystemHeader(DefLoc));
342 }
343 }
344
345 virtual bool shouldMacroBeIncluded(const SourceLocation &MacroLoc,
346 StringRef ModuleName) {
347 return true;
348 }
349
350 ASTContext &Ctx;
351 const SourceManager &SM;
352 APISet &API;
353 Preprocessor &PP;
354};
355
356class APIMacroCallback : public MacroCallback {
357public:
358 APIMacroCallback(ASTContext &Ctx, const SourceManager &SM, APISet &API,
359 Preprocessor &PP, LocationFileChecker &LCF)
360 : MacroCallback(Ctx, SM, API, PP), LCF(LCF) {}
361
362 bool shouldMacroBeIncluded(const SourceLocation &MacroLoc,
363 StringRef ModuleName) override {
364 // Do not include macros from external files
365 return LCF(MacroLoc);
366 }
367
368private:
369 LocationFileChecker &LCF;
370};
371
372std::unique_ptr<llvm::raw_pwrite_stream>
373createAdditionalSymbolGraphFile(CompilerInstance &CI, Twine BaseName) {
374 auto OutputDirectory = CI.getFrontendOpts().SymbolGraphOutputDir;
375
377 llvm::sys::path::append(FileName, OutputDirectory,
378 BaseName + ".symbols.json");
379 return CI.createOutputFile(
380 FileName, /*Binary*/ false, /*RemoveFileOnSignal*/ false,
381 /*UseTemporary*/ true, /*CreateMissingDirectories*/ true);
382}
383
384} // namespace
385
387 SymbolGraphSerializerOption SerializationOptions;
388 SerializationOptions.Compact = !CI.getFrontendOpts().EmitPrettySymbolGraphs;
389 SerializationOptions.EmitSymbolLabelsForTesting =
391
393 auto ConstructOutputFile = [&CI](Twine BaseName) {
394 return createAdditionalSymbolGraphFile(CI, BaseName);
395 };
396
398 *OS, *API, IgnoresList, ConstructOutputFile, SerializationOptions);
399 } else {
401 SerializationOptions);
402 }
403
404 // Flush the stream and close the main output stream.
405 OS.reset();
406}
407
408std::unique_ptr<ASTConsumer>
411
412 if (CI.getFrontendOpts().SymbolGraphOutputDir.empty())
413 OS = CI.createDefaultOutputFile(/*Binary*/ false, InFile,
414 /*Extension*/ "symbols.json",
415 /*RemoveFileOnSignal*/ false,
416 /*CreateMissingDirectories*/ true);
417 else
418 OS = createAdditionalSymbolGraphFile(CI, ProductName);
419
420 if (!OS)
421 return nullptr;
422
423 // Now that we have enough information about the language options and the
424 // target triple, let's create the APISet before anyone uses it.
425 API = std::make_unique<APISet>(
426 CI.getTarget().getTriple(),
427 CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), ProductName);
428
429 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
430
431 CI.getPreprocessor().addPPCallbacks(std::make_unique<APIMacroCallback>(
433 *LCF));
434
435 // Do not include location in anonymous decls.
437 Policy.AnonymousTagNameStyle =
438 llvm::to_underlying(PrintingPolicy::AnonymousTagMode::Plain);
439 CI.getASTContext().setPrintingPolicy(Policy);
440
441 if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
442 llvm::handleAllErrors(
444 CI.getFileManager())
445 .moveInto(IgnoresList),
446 [&CI](const IgnoresFileNotFound &Err) {
447 CI.getDiagnostics().Report(
448 diag::err_extract_api_ignores_file_not_found)
449 << Err.Path;
450 });
451 }
452
453 return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
454 std::move(LCF), *API);
455}
456
457bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) {
458 // Public API can never be inside function bodies, so skip parsing them.
460
461 auto &Inputs = CI.getFrontendOpts().Inputs;
462 if (Inputs.empty())
463 return true;
464
465 if (!CI.hasFileManager())
467
468 auto Kind = Inputs[0].getKind();
469
470 // Convert the header file inputs into a single input buffer.
471 SmallString<256> HeaderContents;
472 bool IsQuoted = false;
473 for (const FrontendInputFile &FIF : Inputs) {
474 if (Kind.isObjectiveC())
475 HeaderContents += "#import";
476 else
477 HeaderContents += "#include";
478
479 StringRef FilePath = FIF.getFile();
480 if (auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
481 if (IsQuoted)
482 HeaderContents += " \"";
483 else
484 HeaderContents += " <";
485
486 HeaderContents += *RelativeName;
487
488 if (IsQuoted)
489 HeaderContents += "\"\n";
490 else
491 HeaderContents += ">\n";
492 KnownInputFiles.emplace_back(static_cast<SmallString<32>>(*RelativeName),
493 IsQuoted);
494 } else {
495 HeaderContents += " \"";
496 HeaderContents += FilePath;
497 HeaderContents += "\"\n";
498 KnownInputFiles.emplace_back(FilePath, true);
499 }
500 }
501
503 CI.getVerboseOutputStream() << getInputBufferName() << ":\n"
504 << HeaderContents << "\n";
505
506 Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
507 getInputBufferName());
508
509 // Set that buffer up as our "real" input in the CompilerInstance.
510 Inputs.clear();
511 Inputs.emplace_back(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false);
512
513 return true;
514}
515
518}
519
520std::unique_ptr<ASTConsumer>
522 StringRef InFile) {
523 auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
524 if (!OtherConsumer)
525 return nullptr;
526
527 CreatedASTConsumer = true;
528
530 auto InputFilename = llvm::sys::path::filename(InFile);
531 OS = createAdditionalSymbolGraphFile(CI, InputFilename);
532
533 // Now that we have enough information about the language options and the
534 // target triple, let's create the APISet before anyone uses it.
535 API = std::make_unique<APISet>(
536 CI.getTarget().getTriple(),
537 CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), ProductName);
538
539 CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
541
542 // Do not include location in anonymous decls.
544 Policy.AnonymousTagNameStyle =
545 llvm::to_underlying(PrintingPolicy::AnonymousTagMode::Plain);
546 CI.getASTContext().setPrintingPolicy(Policy);
547
548 if (!CI.getFrontendOpts().ExtractAPIIgnoresFileList.empty()) {
549 llvm::handleAllErrors(
551 CI.getFileManager())
552 .moveInto(IgnoresList),
553 [&CI](const IgnoresFileNotFound &Err) {
554 CI.getDiagnostics().Report(
555 diag::err_extract_api_ignores_file_not_found)
556 << Err.Path;
557 });
558 }
559
560 auto WrappingConsumer =
561 std::make_unique<WrappingExtractAPIConsumer>(CI.getASTContext(), *API);
562 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
563 Consumers.push_back(std::move(OtherConsumer));
564 Consumers.push_back(std::move(WrappingConsumer));
565
566 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
567}
568
570 // Invoke wrapped action's method.
572
573 if (CreatedASTConsumer) {
575 }
576}
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.
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:899
void setPrintingPolicy(const clang::PrintingPolicy &Policy)
Definition ASTContext.h:903
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.
CompilerInstance & getCompilerInstance() const
virtual void EndSourceFileAction()
Callback at the end of processing a single input.
An input file for the front end.
unsigned SkipFunctionBodies
Skip over function bodies to speed up parsing in cases you do not need them (e.g.
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.
StringRef getName() const
Return the actual identifier string.
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:163
@ 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.
Top level wrappers for InstallAPI frontend operations.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:196
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
Definition TypeBase.h:5988
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.