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 FileNamager!");
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(
const SourceManager &SM, APISet &API, Preprocessor &PP)
286 : SM(SM), API(API), PP(PP) {}
288 void EndOfMainFile()
override {
289 for (
const auto &M : PP.macros()) {
290 auto *II = M.getFirst();
291 auto MD = PP.getMacroDefinition(II);
292 auto *MI = MD.getMacroInfo();
298 if (MI->isUsedForHeaderGuard())
302 if (MI->isBuiltinMacro())
305 auto DefLoc = MI->getDefinitionLoc();
307 if (SM.isInPredefinedFile(DefLoc))
310 auto AssociatedModuleMacros = MD.getModuleMacros();
311 StringRef OwningModuleName;
312 if (!AssociatedModuleMacros.empty())
313 OwningModuleName = AssociatedModuleMacros.back()
315 ->getTopLevelModuleName();
317 if (!shouldMacroBeIncluded(DefLoc, OwningModuleName))
320 StringRef Name = II->getName();
321 PresumedLoc Loc = SM.getPresumedLoc(DefLoc);
322 SmallString<128> USR;
324 API.createRecord<extractapi::MacroDefinitionRecord>(
325 USR, Name, SymbolReference(), Loc,
328 SM.isInSystemHeader(DefLoc));
332 virtual bool shouldMacroBeIncluded(
const SourceLocation &MacroLoc,
333 StringRef ModuleName) {
337 const SourceManager &SM;
342class APIMacroCallback :
public MacroCallback {
344 APIMacroCallback(
const SourceManager &
SM, APISet &API, Preprocessor &PP,
345 LocationFileChecker &LCF)
346 : MacroCallback(
SM, API, PP), LCF(LCF) {}
348 bool shouldMacroBeIncluded(
const SourceLocation &MacroLoc,
349 StringRef ModuleName)
override {
351 return LCF(MacroLoc);
355 LocationFileChecker &LCF;
358std::unique_ptr<llvm::raw_pwrite_stream>
363 llvm::sys::path::append(
FileName, OutputDirectory,
364 BaseName +
".symbols.json");
379 auto ConstructOutputFile = [&CI](Twine BaseName) {
380 return createAdditionalSymbolGraphFile(CI, BaseName);
387 SerializationOptions);
394std::unique_ptr<ASTConsumer>
411 API = std::make_unique<APISet>(
415 auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
426 llvm::handleAllErrors(
431 CI.getDiagnostics().Report(
432 diag::err_extract_api_ignores_file_not_found)
437 return std::make_unique<ExtractAPIConsumer>(CI.
getASTContext(),
438 std::move(LCF), *
API);
450 auto Kind = Inputs[0].getKind();
454 bool IsQuoted =
false;
456 if (Kind.isObjectiveC())
457 HeaderContents +=
"#import";
459 HeaderContents +=
"#include";
461 StringRef FilePath = FIF.getFile();
462 if (
auto RelativeName = getRelativeIncludeName(CI, FilePath, &IsQuoted)) {
464 HeaderContents +=
" \"";
466 HeaderContents +=
" <";
468 HeaderContents += *RelativeName;
471 HeaderContents +=
"\"\n";
473 HeaderContents +=
">\n";
474 KnownInputFiles.emplace_back(
static_cast<SmallString<32>>(*RelativeName),
477 HeaderContents +=
" \"";
478 HeaderContents += FilePath;
479 HeaderContents +=
"\"\n";
480 KnownInputFiles.emplace_back(FilePath,
true);
486 << HeaderContents <<
"\n";
488 Buffer = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
489 getInputBufferName());
493 Inputs.emplace_back(
Buffer->getMemBufferRef(), Kind,
false);
502std::unique_ptr<ASTConsumer>
509 CreatedASTConsumer =
true;
512 auto InputFilename = llvm::sys::path::filename(InFile);
513 OS = createAdditionalSymbolGraphFile(CI, InputFilename);
517 API = std::make_unique<APISet>(
530 llvm::handleAllErrors(
535 CI.getDiagnostics().Report(
536 diag::err_extract_api_ignores_file_not_found)
541 auto WrappingConsumer =
543 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
544 Consumers.push_back(std::move(OtherConsumer));
545 Consumers.push_back(std::move(WrappingConsumer));
547 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
554 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.
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.
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)
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.
unsigned AnonymousTagLocations
When printing an anonymous tag name, also print the location of that entity (e.g.,...