Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 61 additions & 15 deletions clang/lib/Frontend/HeaderIncludeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,22 @@ class HeaderIncludesJSONCallback : public PPCallbacks {
/// an array of separate entries, one for each non-system source file used in
/// the compilation showing only the direct includes and imports from that file.
class HeaderIncludesDirectPerFileCallback : public PPCallbacks {
struct HeaderIncludeInfo {
SourceLocation Location;
FileEntryRef File;
const Module *ImportedModule;

HeaderIncludeInfo(SourceLocation Location, FileEntryRef File,
const Module *ImportedModule)
: Location(Location), File(File), ImportedModule(ImportedModule) {}
};

SourceManager &SM;
HeaderSearch &HSI;
raw_ostream *OutputFile;
bool OwnsOutputFile;
using DependencyMap = llvm::DenseMap<FileEntryRef, SmallVector<FileEntryRef>>;
using DependencyMap =
llvm::DenseMap<FileEntryRef, SmallVector<HeaderIncludeInfo>>;
DependencyMap Dependencies;

public:
Expand Down Expand Up @@ -295,8 +306,8 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
}
}

void HeaderIncludesCallback::FileSkipped(const FileEntryRef &SkippedFile, const
Token &FilenameTok,
void HeaderIncludesCallback::FileSkipped(const FileEntryRef &SkippedFile,
const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) {
if (!DepOpts.ShowSkippedHeaderIncludes)
return;
Expand Down Expand Up @@ -390,18 +401,41 @@ void HeaderIncludesDirectPerFileCallback::EndOfMainFile() {
std::string Str;
llvm::raw_string_ostream OS(Str);
llvm::json::OStream JOS(OS);
JOS.array([&] {
for (auto S = SourceFiles.begin(), SE = SourceFiles.end(); S != SE; ++S) {
JOS.object([&] {
SmallVector<FileEntryRef> &Deps = Dependencies[*S];
JOS.attribute("source", S->getName().str());
JOS.attributeArray("includes", [&] {
for (unsigned I = 0, N = Deps.size(); I != N; ++I)
JOS.value(Deps[I].getName().str());
JOS.object([&] {
JOS.attribute("version", "2.0.0");
JOS.attributeArray("dependencies", [&] {
for (const auto &S : SourceFiles) {
JOS.object([&] {
SmallVector<HeaderIncludeInfo> &Deps = Dependencies[S];
JOS.attribute("source", S.getName().str());
JOS.attributeArray("includes", [&] {
for (unsigned I = 0, N = Deps.size(); I != N; ++I) {
if (!Deps[I].ImportedModule) {
JOS.object([&] {
JOS.attribute("location", Deps[I].Location.printToString(SM));
JOS.attribute("file", Deps[I].File.getName());
});
}
}
});
JOS.attributeArray("imports", [&] {
for (unsigned I = 0, N = Deps.size(); I != N; ++I) {
if (Deps[I].ImportedModule) {
JOS.object([&] {
JOS.attribute("location", Deps[I].Location.printToString(SM));
JOS.attribute(
"module",
Deps[I].ImportedModule->getTopLevelModuleName());
JOS.attribute("file", Deps[I].File.getName());
});
}
}
});
});
});
}
}
});
});

OS << "\n";

if (OutputFile->get_kind() == raw_ostream::OStreamKind::OK_FDStream) {
Expand All @@ -427,7 +461,18 @@ void HeaderIncludesDirectPerFileCallback::InclusionDirective(
if (!FromFile)
return;

Dependencies[*FromFile].push_back(*File);
FileEntryRef HeaderOrModuleMapFile = *File;
if (ModuleImported && SuggestedModule) {
OptionalFileEntryRef ModuleMapFile =
HSI.getModuleMap().getModuleMapFileForUniquing(SuggestedModule);
if (ModuleMapFile) {
HeaderOrModuleMapFile = *ModuleMapFile;
}
}

HeaderIncludeInfo DependenciesEntry(
Loc, HeaderOrModuleMapFile, (ModuleImported ? SuggestedModule : nullptr));
Dependencies[*FromFile].push_back(DependenciesEntry);
}

void HeaderIncludesDirectPerFileCallback::moduleImport(SourceLocation ImportLoc,
Expand All @@ -448,5 +493,6 @@ void HeaderIncludesDirectPerFileCallback::moduleImport(SourceLocation ImportLoc,
if (!ModuleMapFile)
return;

Dependencies[*FromFile].push_back(*ModuleMapFile);
HeaderIncludeInfo DependenciesEntry(Loc, *ModuleMapFile, Imported);
Dependencies[*FromFile].push_back(DependenciesEntry);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module module0 {
header "header0.h"
header "header1.h"
export *
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module systemmodule0 {
header "system2.h"
export *
}
7 changes: 6 additions & 1 deletion clang/test/Preprocessor/print-header-json.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@
#include "header0.h"
#include "system2.h"

// RUN: rm %t.txt
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is brittle and in incremental build + test using the cached PCMs in %t after a binary change to the PCMs will result in memory corruption and random CI failures. I will send a fix for this.

cc @thurstond

// RUN: env CC_PRINT_HEADERS_FORMAT=json CC_PRINT_HEADERS_FILTERING=direct-per-file CC_PRINT_HEADERS_FILE=%t.txt %clang -fsyntax-only -I %S/Inputs/print-header-json -isystem %S/Inputs/print-header-json/system -fmodules -fimplicit-module-maps -fmodules-cache-path=%t %s -o /dev/null
// RUN: cat %t.txt | FileCheck %s --check-prefix=SUPPORTED_PERFILE_MODULES

// SUPPORTED: {"source":"{{[^,]*}}print-header-json.c","includes":["{{[^,]*}}system0.h","{{[^,]*}}system3.h","{{[^,]*}}system2.h"]}
// SUPPORTED_PERFILE: [{"source":"{{[^,]*}}print-header-json.c","includes":["{{[^,]*}}system0.h","{{[^,]*}}header0.h","{{[^,]*}}system2.h"]},{"source":"{{[^,]*}}header0.h","includes":["{{[^,]*}}system3.h","{{[^,]*}}header1.h","{{[^,]*}}header2.h"]}]
// SUPPORTED_PERFILE: {"version":"2.0.0","dependencies":[{"source":"{{[^,]*}}print-header-json.c","includes":[{"location":"{{[^,]*}}print-header-json.c:20:1","file":"{{[^,]*}}system0.h"},{"location":"{{[^,]*}}print-header-json.c:21:1","file":"{{[^,]*}}header0.h"},{"location":"{{[^,]*}}print-header-json.c:22:1","file":"{{[^,]*}}system2.h"}],"imports":[]},{"source":"{{[^,]*}}header0.h","includes":[{"location":"{{[^,]*}}header0.h:1:1","file":"{{[^,]*}}system3.h"},{"location":"{{[^,]*}}header0.h:2:1","file":"{{[^,]*}}header1.h"},{"location":"{{[^,]*}}header0.h:3:1","file":"{{[^,]*}}header2.h"}],"imports":[]}]}
// SUPPORTED_PERFILE_MODULES: {"version":"2.0.0","dependencies":[{"source":"{{[^,]*}}print-header-json.c","includes":[{"location":"{{[^,]*}}print-header-json.c:20:1","file":"{{[^,]*}}system0.h"}],"imports":[{"location":"{{[^,]*}}print-header-json.c:21:1","module":"module0","file":"{{[^,]*}}print-header-json{{[\/\\]+}}module.modulemap"},{"location":"{{[^,]*}}print-header-json.c:22:1","module":"systemmodule0","file":"{{[^,]*}}print-header-json{{[\/\\]+}}system{{[\/\\]+}}module.modulemap"}]}]}

// UNSUPPORTED0: error: unsupported combination: -header-include-format=textual and -header-include-filtering=only-direct-system
// UNSUPPORTED1: error: unsupported combination: -header-include-format=json and -header-include-filtering=none
Expand Down