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)
221 KnownFileEntries.insert(*FE);
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) {}
290 for (
const auto &M : PP.macros()) {
291 auto *II = M.getFirst();
292 auto MD = PP.getMacroDefinition(II);
293 auto *MI = MD.getMacroInfo();
299 if (MI->isUsedForHeaderGuard())
303 if (MI->isBuiltinMacro())
306 auto DefLoc = MI->getDefinitionLoc();
308 if (
SM.isWrittenInBuiltinFile(DefLoc) ||
309 SM.isWrittenInCommandLineFile(DefLoc))
312 auto AssociatedModuleMacros = MD.getModuleMacros();
313 StringRef OwningModuleName;
314 if (!AssociatedModuleMacros.empty())
315 OwningModuleName = AssociatedModuleMacros.back()
317 ->getTopLevelModuleName();
319 if (!shouldMacroBeIncluded(DefLoc, OwningModuleName))
322 StringRef Name = II->getName();
330 SM.isInSystemHeader(DefLoc));
334 virtual bool shouldMacroBeIncluded(
const SourceLocation &MacroLoc,
335 StringRef ModuleName) {
344class APIMacroCallback :
public MacroCallback {
347 LocationFileChecker &LCF)
348 : MacroCallback(
SM, API, PP), LCF(LCF) {}
351 StringRef ModuleName)
override {
353 return LCF(MacroLoc);
357 LocationFileChecker &LCF;
360std::unique_ptr<llvm::raw_pwrite_stream>
365 llvm::sys::path::append(
FileName, OutputDirectory,
366 BaseName +
".symbols.json");
381 auto ConstructOutputFile = [&CI](Twine BaseName) {
382 return createAdditionalSymbolGraphFile(CI, BaseName);
389 SerializationOptions);
396std::unique_ptr<ASTConsumer>
413 API = std::make_unique<APISet>(
417 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
428 llvm::handleAllErrors(
433 CI.getDiagnostics().Report(
434 diag::err_extract_api_ignores_file_not_found)
439 return std::make_unique<ExtractAPIConsumer>(CI.
getASTContext(),
440 std::move(LCF), *
API);
452 auto Kind = Inputs[0].getKind();
456 bool IsQuoted =
false;
458 if (Kind.isObjectiveC())
459 HeaderContents +=
"#import";
461 HeaderContents +=
"#include";
463 StringRef FilePath = FIF.getFile();
464 if (
auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
466 HeaderContents +=
" \"";
468 HeaderContents +=
" <";
470 HeaderContents += *RelativeName;
473 HeaderContents +=
"\"\n";
475 HeaderContents +=
">\n";
476 KnownInputFiles.emplace_back(
static_cast<SmallString<32>>(*RelativeName),
479 HeaderContents +=
" \"";
480 HeaderContents += FilePath;
481 HeaderContents +=
"\"\n";
482 KnownInputFiles.emplace_back(FilePath,
true);
488 << HeaderContents <<
"\n";
490 Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
491 getInputBufferName());
495 Inputs.emplace_back(
Buffer->getMemBufferRef(), Kind,
false);
500void ExtractAPIAction::EndSourceFileAction() {
504std::unique_ptr<ASTConsumer>
511 CreatedASTConsumer =
true;
514 auto InputFilename = llvm::sys::path::filename(InFile);
515 OS = createAdditionalSymbolGraphFile(CI, InputFilename);
519 API = std::make_unique<APISet>(
532 llvm::handleAllErrors(
537 CI.getDiagnostics().Report(
538 diag::err_extract_api_ignores_file_not_found)
543 auto WrappingConsumer =
545 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
546 Consumers.push_back(std::move(OtherConsumer));
547 Consumers.push_back(std::move(WrappingConsumer));
549 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
552void WrappingExtractAPIAction::EndSourceFileAction() {
556 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...
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.
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
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.
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.
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.,...