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"
61 bool *IsQuoted =
nullptr) {
63 "CompilerInstance does not have a FileManager!");
65 using namespace llvm::sys;
69 FS.makeAbsolute(FilePath);
70 path::remove_dots(FilePath,
true);
71 FilePath = path::convert_to_slash(FilePath);
76 auto CheckDir = [&](llvm::StringRef Dir) ->
unsigned {
78 FS.makeAbsolute(DirPath);
79 path::remove_dots(DirPath,
true);
81 for (
auto NI = path::begin(
File), NE = path::end(
File),
82 DI = path::begin(Dir), DE = path::end(Dir);
85 while (NI != NE && *NI ==
".")
91 while (DI != DE && *DI ==
".")
97 return NI - path::begin(
File);
100 if (NI->size() == 1 && DI->size() == 1 &&
101 path::is_separator(NI->front()) && path::is_separator(DI->front()))
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))
120 unsigned PrefixLength = 0;
133 StringRef SpelledFilename = HMap->reverseLookupFilename(
File);
134 if (!SpelledFilename.empty())
135 return SpelledFilename.str();
143 PrefixLength = CheckDir(Entry.Path);
144 if (PrefixLength > 0) {
147 if (Entry.IsFramework) {
152 if (Matches.size() != 4)
155 return path::convert_to_slash(
156 (Matches[1].drop_front(Matches[1].rfind(
'/') + 1) +
"/" +
163 return path::convert_to_slash(
File.drop_front(PrefixLength));
171std::optional<std::string> getRelativeIncludeName(
const CompilerInstance &CI,
173 bool *IsQuoted =
nullptr) {
177struct LocationFileChecker {
178 bool operator()(SourceLocation Loc) {
181 auto &SM = CI.getSourceManager();
182 auto FileLoc = SM.getFileLoc(Loc);
183 FileID FID = SM.getFileID(FileLoc);
191 if (KnownFileEntries.count(*
File))
194 if (ExternalFileEntries.count(*
File))
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;
205 KnownFileEntries.insert(*
File);
211 ExternalFileEntries.insert(*
File);
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);
224 const CompilerInstance &CI;
225 SmallVector<std::pair<SmallString<32>,
bool>> &KnownFiles;
226 llvm::DenseSet<const FileEntry *> KnownFileEntries;
227 llvm::DenseSet<const FileEntry *> ExternalFileEntries;
231 bool shouldDeclBeIncluded(
const Decl *D)
const {
232 bool ShouldBeIncluded =
true;
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();
241 ShouldBeIncluded = ShouldBeIncluded && LCF(D->
getLocation());
242 return ShouldBeIncluded;
245 BatchExtractAPIVisitor(LocationFileChecker &LCF, ASTContext &Context,
247 : ExtractAPIVisitor<BatchExtractAPIVisitor>(Context, API), LCF(LCF) {}
250 LocationFileChecker &LCF;
253class WrappingExtractAPIConsumer :
public ASTConsumer {
255 WrappingExtractAPIConsumer(ASTContext &Context, APISet &API)
256 : Visitor(Context, API) {}
258 void HandleTranslationUnit(ASTContext &Context)
override {
264 ExtractAPIVisitor<> Visitor;
269 ExtractAPIConsumer(ASTContext &Context,
270 std::unique_ptr<LocationFileChecker> LCF, APISet &API)
271 : Visitor(*LCF, Context, API), LCF(std::move(LCF)) {}
273 void HandleTranslationUnit(ASTContext &Context)
override {
279 BatchExtractAPIVisitor Visitor;
280 std::unique_ptr<LocationFileChecker> LCF;
285 MacroCallback(ASTContext &Ctx,
const SourceManager &SM, APISet &API,
287 : Ctx(Ctx), SM(SM), API(API), PP(PP) {}
289 void EndOfMainFile()
override {
290 SmallVector<const IdentifierInfo *>
Macros;
291 for (
const auto &M : PP.macros())
292 Macros.push_back(M.getFirst());
294 [](
const IdentifierInfo *LHS,
const IdentifierInfo *RHS) {
298 for (
const auto *II : Macros) {
299 auto MD = PP.getMacroDefinition(II);
300 auto *MI = MD.getMacroInfo();
306 if (MI->isUsedForHeaderGuard())
310 if (MI->isBuiltinMacro())
313 auto DefLoc = MI->getDefinitionLoc();
315 if (SM.isInPredefinedFile(DefLoc))
318 auto AssociatedModuleMacros = MD.getModuleMacros();
319 StringRef OwningModuleName;
320 if (!AssociatedModuleMacros.empty())
321 OwningModuleName = AssociatedModuleMacros.back()
323 ->getTopLevelModuleName();
325 if (!shouldMacroBeIncluded(DefLoc, OwningModuleName))
328 StringRef Name = II->getName();
329 PresumedLoc Loc = SM.getPresumedLoc(DefLoc);
330 SmallString<128> USR;
334 if (
const auto *RC = Ctx.getRawCommentForAnyRedecl(MI))
335 Comment = RC->getFormattedLines(SM, Ctx.getDiagnostics());
337 API.createRecord<extractapi::MacroDefinitionRecord>(
338 USR, Name, SymbolReference(), Loc, Comment,
341 SM.isInSystemHeader(DefLoc));
345 virtual bool shouldMacroBeIncluded(
const SourceLocation &MacroLoc,
346 StringRef ModuleName) {
351 const SourceManager &SM;
356class APIMacroCallback :
public MacroCallback {
358 APIMacroCallback(ASTContext &Ctx,
const SourceManager &SM, APISet &API,
359 Preprocessor &PP, LocationFileChecker &LCF)
360 : MacroCallback(Ctx, SM, API, PP), LCF(LCF) {}
362 bool shouldMacroBeIncluded(
const SourceLocation &MacroLoc,
363 StringRef ModuleName)
override {
365 return LCF(MacroLoc);
369 LocationFileChecker &LCF;
372std::unique_ptr<llvm::raw_pwrite_stream>
377 llvm::sys::path::append(
FileName, OutputDirectory,
378 BaseName +
".symbols.json");
393 auto ConstructOutputFile = [&CI](Twine BaseName) {
394 return createAdditionalSymbolGraphFile(CI, BaseName);
401 SerializationOptions);
408std::unique_ptr<ASTConsumer>
425 API = std::make_unique<APISet>(
429 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
442 llvm::handleAllErrors(
447 CI.getDiagnostics().Report(
448 diag::err_extract_api_ignores_file_not_found)
453 return std::make_unique<ExtractAPIConsumer>(CI.
getASTContext(),
454 std::move(LCF), *
API);
468 auto Kind = Inputs[0].getKind();
472 bool IsQuoted =
false;
474 if (Kind.isObjectiveC())
475 HeaderContents +=
"#import";
477 HeaderContents +=
"#include";
479 StringRef FilePath = FIF.getFile();
480 if (
auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
482 HeaderContents +=
" \"";
484 HeaderContents +=
" <";
486 HeaderContents += *RelativeName;
489 HeaderContents +=
"\"\n";
491 HeaderContents +=
">\n";
492 KnownInputFiles.emplace_back(
static_cast<SmallString<32>>(*RelativeName),
495 HeaderContents +=
" \"";
496 HeaderContents += FilePath;
497 HeaderContents +=
"\"\n";
498 KnownInputFiles.emplace_back(FilePath,
true);
504 << HeaderContents <<
"\n";
506 Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
507 getInputBufferName());
511 Inputs.emplace_back(
Buffer->getMemBufferRef(), Kind,
false);
520std::unique_ptr<ASTConsumer>
527 CreatedASTConsumer =
true;
530 auto InputFilename = llvm::sys::path::filename(InFile);
531 OS = createAdditionalSymbolGraphFile(CI, InputFilename);
535 API = std::make_unique<APISet>(
549 llvm::handleAllErrors(
554 CI.getDiagnostics().Report(
555 diag::err_extract_api_ignores_file_not_found)
560 auto WrappingConsumer =
562 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
563 Consumers.push_back(std::move(OtherConsumer));
564 Consumers.push_back(std::move(WrappingConsumer));
566 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
573 if (CreatedASTConsumer) {
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.
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.
TranslationUnitDecl * getTranslationUnitDecl() const
const clang::PrintingPolicy & getPrintingPolicy() const
void setPrintingPolicy(const clang::PrintingPolicy &Policy)
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...
bool hasFileManager() const
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
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
StringRef getNameAsRequested() const
The name of this FileEntry, as originally requested without applying any remappings for VFS 'use-exte...
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.
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.
std::string SymbolGraphOutputDir
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
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.
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.
Defines the clang::TargetInfo interface.
@ Macros
Canonicalize -D and -U options.
@ 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
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
Describes how types, statements, expressions, and declarations should be printed.
@ Plain
E.g., (anonymous enum)/(unnamed struct)/etc.
unsigned AnonymousTagNameStyle