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 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.isInPredefinedFile(DefLoc))
311 auto AssociatedModuleMacros = MD.getModuleMacros();
312 StringRef OwningModuleName;
313 if (!AssociatedModuleMacros.empty())
314 OwningModuleName = AssociatedModuleMacros.back()
316 ->getTopLevelModuleName();
318 if (!shouldMacroBeIncluded(DefLoc, OwningModuleName))
321 StringRef Name = II->getName();
322 PresumedLoc Loc = SM.getPresumedLoc(DefLoc);
323 SmallString<128> USR;
327 if (
const auto *RC = Ctx.getRawCommentForAnyRedecl(MI))
328 Comment = RC->getFormattedLines(SM, Ctx.getDiagnostics());
330 API.createRecord<extractapi::MacroDefinitionRecord>(
331 USR, Name, SymbolReference(), Loc, Comment,
334 SM.isInSystemHeader(DefLoc));
338 virtual bool shouldMacroBeIncluded(
const SourceLocation &MacroLoc,
339 StringRef ModuleName) {
344 const SourceManager &SM;
349class APIMacroCallback :
public MacroCallback {
351 APIMacroCallback(ASTContext &Ctx,
const SourceManager &
SM, APISet &API,
352 Preprocessor &PP, LocationFileChecker &LCF)
353 : MacroCallback(Ctx,
SM, API, PP), LCF(LCF) {}
355 bool shouldMacroBeIncluded(
const SourceLocation &MacroLoc,
356 StringRef ModuleName)
override {
358 return LCF(MacroLoc);
362 LocationFileChecker &LCF;
365std::unique_ptr<llvm::raw_pwrite_stream>
370 llvm::sys::path::append(
FileName, OutputDirectory,
371 BaseName +
".symbols.json");
386 auto ConstructOutputFile = [&CI](Twine BaseName) {
387 return createAdditionalSymbolGraphFile(CI, BaseName);
394 SerializationOptions);
401std::unique_ptr<ASTConsumer>
418 API = std::make_unique<APISet>(
422 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
435 llvm::handleAllErrors(
440 CI.getDiagnostics().Report(
441 diag::err_extract_api_ignores_file_not_found)
446 return std::make_unique<ExtractAPIConsumer>(CI.
getASTContext(),
447 std::move(LCF), *
API);
458 auto Kind = Inputs[0].getKind();
462 bool IsQuoted =
false;
464 if (Kind.isObjectiveC())
465 HeaderContents +=
"#import";
467 HeaderContents +=
"#include";
469 StringRef FilePath = FIF.getFile();
470 if (
auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
472 HeaderContents +=
" \"";
474 HeaderContents +=
" <";
476 HeaderContents += *RelativeName;
479 HeaderContents +=
"\"\n";
481 HeaderContents +=
">\n";
482 KnownInputFiles.emplace_back(
static_cast<SmallString<32>>(*RelativeName),
485 HeaderContents +=
" \"";
486 HeaderContents += FilePath;
487 HeaderContents +=
"\"\n";
488 KnownInputFiles.emplace_back(FilePath,
true);
494 << HeaderContents <<
"\n";
496 Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
497 getInputBufferName());
501 Inputs.emplace_back(
Buffer->getMemBufferRef(), Kind,
false);
510std::unique_ptr<ASTConsumer>
517 CreatedASTConsumer =
true;
520 auto InputFilename = llvm::sys::path::filename(InFile);
521 OS = createAdditionalSymbolGraphFile(CI, InputFilename);
525 API = std::make_unique<APISet>(
539 llvm::handleAllErrors(
544 CI.getDiagnostics().Report(
545 diag::err_extract_api_ignores_file_not_found)
550 auto WrappingConsumer =
552 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
553 Consumers.push_back(std::move(OtherConsumer));
554 Consumers.push_back(std::move(WrappingConsumer));
556 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
563 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.
virtual void EndSourceFileAction()
Callback at the end of processing a single input.
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.
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.
@ 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.
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