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/FileSystem.h"
47#include "llvm/Support/MemoryBuffer.h"
48#include "llvm/Support/Path.h"
49#include "llvm/Support/Regex.h"
50#include "llvm/Support/raw_ostream.h"
56using namespace extractapi;
62 bool *IsQuoted =
nullptr) {
64 "CompilerInstance does not have a FileNamager!");
66 using namespace llvm::sys;
70 FS.makeAbsolute(FilePath);
71 path::remove_dots(FilePath,
true);
72 FilePath = path::convert_to_slash(FilePath);
77 auto CheckDir = [&](llvm::StringRef Dir) ->
unsigned {
79 FS.makeAbsolute(DirPath);
80 path::remove_dots(DirPath,
true);
82 for (
auto NI = path::begin(
File), NE = path::end(
File),
83 DI = path::begin(Dir), DE = path::end(Dir);
86 while (NI != NE && *NI ==
".")
92 while (DI != DE && *DI ==
".")
98 return NI - path::begin(
File);
101 if (NI->size() == 1 && DI->size() == 1 &&
102 path::is_separator(NI->front()) && path::is_separator(DI->front()))
108 if (NI->ends_with(
".sdk") && DI->ends_with(
".sdk")) {
109 StringRef NBasename = path::stem(*NI);
110 StringRef DBasename = path::stem(*DI);
111 if (DBasename.starts_with(NBasename))
121 unsigned PrefixLength = 0;
134 StringRef SpelledFilename = HMap->reverseLookupFilename(
File);
135 if (!SpelledFilename.empty())
136 return SpelledFilename.str();
144 PrefixLength = CheckDir(Entry.Path);
145 if (PrefixLength > 0) {
148 if (Entry.IsFramework) {
153 if (Matches.size() != 4)
156 return path::convert_to_slash(
157 (Matches[1].drop_front(Matches[1].rfind(
'/') + 1) +
"/" +
164 return path::convert_to_slash(
File.drop_front(PrefixLength));
172std::optional<std::string> getRelativeIncludeName(
const CompilerInstance &CI,
174 bool *IsQuoted =
nullptr) {
178struct LocationFileChecker {
183 auto FileLoc =
SM.getFileLoc(
Loc);
192 if (KnownFileEntries.count(*
File))
195 if (ExternalFileEntries.count(*
File))
199 bool IsQuoted =
false;
200 if (
auto IncludeName = getRelativeIncludeName(CI, *
File, &IsQuoted))
201 if (llvm::any_of(KnownFiles,
202 [&IsQuoted, &IncludeName](
const auto &KnownFile) {
203 return KnownFile.first.equals(*IncludeName) &&
204 KnownFile.second == IsQuoted;
206 KnownFileEntries.insert(*
File);
212 ExternalFileEntries.insert(*
File);
218 : CI(CI), KnownFiles(KnownFiles), ExternalFileEntries() {
219 for (
const auto &KnownFile : KnownFiles)
227 llvm::DenseSet<const FileEntry *> KnownFileEntries;
228 llvm::DenseSet<const FileEntry *> ExternalFileEntries;
233 bool ShouldBeIncluded =
true;
235 if (
auto *TD = llvm::dyn_cast<TagDecl>(
D))
236 ShouldBeIncluded = TD->isThisDeclarationADefinition();
237 else if (
auto *
Interface = llvm::dyn_cast<ObjCInterfaceDecl>(
D))
238 ShouldBeIncluded =
Interface->isThisDeclarationADefinition();
239 else if (
auto *Protocol = llvm::dyn_cast<ObjCProtocolDecl>(
D))
240 ShouldBeIncluded =
Protocol->isThisDeclarationADefinition();
242 ShouldBeIncluded = ShouldBeIncluded && LCF(
D->
getLocation());
243 return ShouldBeIncluded;
246 BatchExtractAPIVisitor(LocationFileChecker &LCF,
ASTContext &Context,
251 LocationFileChecker &LCF;
254class WrappingExtractAPIConsumer :
public ASTConsumer {
257 : Visitor(Context, API) {}
271 std::unique_ptr<LocationFileChecker> LCF,
APISet &API)
272 : Visitor(*LCF, Context, API), LCF(
std::move(LCF)) {}
280 BatchExtractAPIVisitor Visitor;
281 std::unique_ptr<LocationFileChecker> LCF;
287 :
SM(
SM), API(API), PP(PP) {}
297 if (
SM.isWrittenInBuiltinFile(SourceLoc) ||
298 SM.isWrittenInCommandLineFile(SourceLoc))
301 PendingMacros.emplace_back(MacroNameToken, MD);
314 llvm::erase_if(PendingMacros, [&MD,
this](
const PendingMacro &PM) {
315 return MD.
getMacroInfo()->isIdenticalTo(*PM.MD->getMacroInfo(), PP,
321 for (
auto &PM : PendingMacros) {
324 if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
327 if (!shouldMacroBeIncluded(PM))
330 StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
340 SM.isInSystemHeader(PM.MacroNameToken.getLocation()));
343 PendingMacros.clear();
347 struct PendingMacro {
348 Token MacroNameToken;
352 : MacroNameToken(MacroNameToken), MD(MD) {}
355 virtual bool shouldMacroBeIncluded(
const PendingMacro &PM) {
return true; }
363class APIMacroCallback :
public MacroCallback {
366 LocationFileChecker &LCF)
367 : MacroCallback(
SM, API, PP), LCF(LCF) {}
369 bool shouldMacroBeIncluded(
const PendingMacro &PM)
override {
371 return LCF(PM.MacroNameToken.getLocation());
375 LocationFileChecker &LCF;
378std::unique_ptr<llvm::raw_pwrite_stream>
383 llvm::sys::path::append(
FileName, OutputDirectory,
384 BaseName +
".symbols.json");
399 auto ConstructOutputFile = [&CI](Twine BaseName) {
400 return createAdditionalSymbolGraphFile(CI, BaseName);
407 SerializationOptions);
414std::unique_ptr<ASTConsumer>
431 API = std::make_unique<APISet>(
435 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
446 llvm::handleAllErrors(
451 CI.getDiagnostics().Report(
452 diag::err_extract_api_ignores_file_not_found)
457 return std::make_unique<ExtractAPIConsumer>(CI.
getASTContext(),
458 std::move(LCF), *
API);
470 auto Kind = Inputs[0].getKind();
474 bool IsQuoted =
false;
476 if (Kind.isObjectiveC())
477 HeaderContents +=
"#import";
479 HeaderContents +=
"#include";
481 StringRef FilePath = FIF.getFile();
482 if (
auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
484 HeaderContents +=
" \"";
486 HeaderContents +=
" <";
488 HeaderContents += *RelativeName;
491 HeaderContents +=
"\"\n";
493 HeaderContents +=
">\n";
494 KnownInputFiles.emplace_back(
static_cast<SmallString<32>>(*RelativeName),
497 HeaderContents +=
" \"";
498 HeaderContents += FilePath;
499 HeaderContents +=
"\"\n";
500 KnownInputFiles.emplace_back(FilePath,
true);
506 << HeaderContents <<
"\n";
508 Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
509 getInputBufferName());
513 Inputs.emplace_back(
Buffer->getMemBufferRef(), Kind,
false);
518void ExtractAPIAction::EndSourceFileAction() {
522std::unique_ptr<ASTConsumer>
529 CreatedASTConsumer =
true;
532 auto InputFilename = llvm::sys::path::filename(InFile);
533 OS = createAdditionalSymbolGraphFile(CI, InputFilename);
537 API = std::make_unique<APISet>(
550 llvm::handleAllErrors(
555 CI.getDiagnostics().Report(
556 diag::err_extract_api_ignores_file_not_found)
561 auto WrappingConsumer =
563 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
564 Consumers.push_back(std::move(OtherConsumer));
565 Consumers.push_back(std::move(WrappingConsumer));
567 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
570void WrappingExtractAPIAction::EndSourceFileAction() {
574 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.
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
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.
FileManager * createFileManager(IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS=nullptr)
Create the file manager and replace any existing one with it.
bool hasFileManager() const
raw_ostream & getVerboseOutputStream()
Get the current stream for verbose output.
std::unique_ptr< raw_pwrite_stream > createDefaultOutputFile(bool Binary=true, StringRef BaseInput="", StringRef Extension="", bool RemoveFileOnSignal=true, bool CreateMissingDirectories=false, bool ForceUseTemporary=false)
Create the default output file (from the invocation's options) and add it to the list of tracked outp...
FileManager & getFileManager() const
Return the current file manager to the caller.
std::unique_ptr< raw_pwrite_stream > createOutputFile(StringRef OutputPath, bool Binary, bool RemoveFileOnSignal, bool UseTemporary, bool CreateMissingDirectories=false)
Create a new output file, optionally deriving the output path name, and add it to the list of tracked...
Preprocessor & getPreprocessor() const
Return the current preprocessor.
ASTContext & getASTContext() const
FrontendOptions & getFrontendOpts()
HeaderSearchOptions & getHeaderSearchOpts()
TargetInfo & getTarget() const
llvm::vfs::FileSystem & getVirtualFileSystem() const
SourceManager & getSourceManager() const
Return the current source manager.
Decl - This represents one declaration (or definition), e.g.
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...
Cached information about one file (either on disk or in the virtual file system).
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
CompilerInstance & getCompilerInstance() const
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
A description of the current definition of a macro.
MacroInfo * getMacroInfo() const
Get the MacroInfo that should be used for this definition.
Encapsulates changes to the "macros namespace" (the location where the macro name became active,...
const MacroInfo * getMacroInfo() const
Encapsulates the data about a macro definition (e.g.
bool isBuiltinMacro() const
Return true if this macro requires processing before expansion.
This interface provides a way to observe the actions of the preprocessor as it does its thing.
virtual void EndOfMainFile()
Callback invoked when the end of the main file is reached.
virtual void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, const MacroDirective *Undef)
Hook called whenever a macro #undef is seen.
virtual void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD)
Hook called whenever a macro definition is seen.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
Represents an unpacked "presumed" location which can be presented to the user.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Token - This structure provides full information about a lexed token.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
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.
@ 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.
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
Describes how types, statements, expressions, and declarations should be printed.
unsigned AnonymousTagLocations
When printing an anonymous tag name, also print the location of that entity (e.g.,...