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"
55 using namespace clang;
56 using namespace extractapi;
60 std::optional<std::string> getRelativeIncludeName(
const CompilerInstance &CI,
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));
172 std::optional<std::string> getRelativeIncludeName(
const CompilerInstance &CI,
174 bool *IsQuoted =
nullptr) {
178 struct 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)
232 bool shouldDeclBeIncluded(
const Decl *D)
const {
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;
254 class WrappingExtractAPIConsumer :
public ASTConsumer {
257 : Visitor(Context, API) {}
259 void HandleTranslationUnit(
ASTContext &Context)
override {
271 std::unique_ptr<LocationFileChecker> LCF,
APISet &API)
272 : Visitor(*LCF, Context, API), LCF(
std::move(LCF)) {}
274 void HandleTranslationUnit(
ASTContext &Context)
override {
280 BatchExtractAPIVisitor Visitor;
281 std::unique_ptr<LocationFileChecker> LCF;
287 :
SM(
SM), API(API), PP(PP) {}
289 void MacroDefined(
const Token &MacroNameToken,
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,
320 void EndOfMainFile()
override {
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; }
363 class 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;
378 std::unique_ptr<llvm::raw_pwrite_stream>
383 llvm::sys::path::append(FileName, OutputDirectory,
384 BaseName +
".symbols.json");
386 FileName,
false,
false,
399 auto ConstructOutputFile = [&CI](Twine BaseName) {
400 return createAdditionalSymbolGraphFile(CI, BaseName);
404 *OS, *API, IgnoresList, ConstructOutputFile, SerializationOptions);
407 SerializationOptions);
414 std::unique_ptr<ASTConsumer>
424 OS = createAdditionalSymbolGraphFile(CI, ProductName);
431 API = std::make_unique<APISet>(
435 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
446 llvm::handleAllErrors(
449 .moveInto(IgnoresList),
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);
518 void ExtractAPIAction::EndSourceFileAction() {
519 ImplEndSourceFileAction(getCompilerInstance());
522 std::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(
553 .moveInto(IgnoresList),
555 CI.getDiagnostics().Report(
556 diag::err_extract_api_ignores_file_not_found)
561 auto WrappingConsumer =
562 std::make_unique<WrappingExtractAPIConsumer>(CI.
getASTContext(), *API);
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));
570 void WrappingExtractAPIAction::EndSourceFileAction() {
574 if (CreatedASTConsumer) {
575 ImplEndSourceFileAction(getCompilerInstance());
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.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const clang::PrintingPolicy & getPrintingPolicy() const
void setPrintingPolicy(const clang::PrintingPolicy &Policy)
TranslationUnitDecl * getTranslationUnitDecl() const
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.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
bool hasFileManager() const
TargetInfo & getTarget() const
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...
FrontendOptions & getFrontendOpts()
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...
ASTContext & getASTContext() const
SourceManager & getSourceManager() const
Return the current source manager.
FileManager & getFileManager() const
Return the current file manager to the caller.
HeaderSearchOptions & getHeaderSearchOpts()
raw_ostream & getVerboseOutputStream()
Get the current stream for verbose output.
llvm::vfs::FileSystem & getVirtualFileSystem() const
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).
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.
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.
bool NE(InterpState &S, CodePtr OpPC)
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.,...