Skip to content

Commit f544810

Browse files
committed
[WIP] Implement print-deserialized-declarations flag to dump source ranges of decls read during AST deserialization.
1 parent 809f857 commit f544810

File tree

4 files changed

+160
-3
lines changed

4 files changed

+160
-3
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7968,6 +7968,10 @@ def print_dependency_directives_minimized_source : Flag<["-"],
79687968
"print-dependency-directives-minimized-source">,
79697969
HelpText<"Print the output of the dependency directives source minimizer">;
79707970
}
7971+
def print_deserialized_declarations : Joined<["-"],
7972+
"print-deserialized-declarations-path=">,
7973+
HelpText<"Print traces of deserialized declarations to aid debugging and minimization">,
7974+
MarshallingInfoString<FrontendOpts<"PrintDeserializedDeclarationsPath">>;
79717975

79727976
defm emit_llvm_uselists : BoolOption<"", "emit-llvm-uselists",
79737977
CodeGenOpts<"EmitLLVMUseLists">, DefaultFalse,

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,9 @@ class FrontendOptions {
530530
/// Output Path for module output file.
531531
std::string ModuleOutputPath;
532532

533+
/// Output path to print deserialized declarations.
534+
std::string PrintDeserializedDeclarationsPath;
535+
533536
public:
534537
FrontendOptions()
535538
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,6 +2975,11 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
29752975
#undef FRONTEND_OPTION_WITH_MARSHALLING
29762976

29772977
Opts.ProgramAction = frontend::ParseSyntaxOnly;
2978+
// if (Args.hasArg(OPT_print_deserialized_declarations)) {
2979+
// llvm::errs() << "FLAG SET!!!\n";
2980+
// FrontendOpts.PrintDeserializedDeclarations = true;
2981+
// }
2982+
29782983
if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {
29792984
OptSpecifier Opt = OptSpecifier(A->getOption().getID());
29802985
std::optional<frontend::ActionKind> ProgramAction = getFrontendAction(Opt);

clang/lib/Frontend/FrontendAction.cpp

Lines changed: 148 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/Basic/FileEntry.h"
1616
#include "clang/Basic/LangStandard.h"
1717
#include "clang/Basic/Sarif.h"
18+
#include "clang/Basic/SourceManager.h"
1819
#include "clang/Basic/Stack.h"
1920
#include "clang/Frontend/ASTUnit.h"
2021
#include "clang/Frontend/CompilerInstance.h"
@@ -35,6 +36,7 @@
3536
#include "clang/Serialization/ASTReader.h"
3637
#include "clang/Serialization/GlobalModuleIndex.h"
3738
#include "llvm/ADT/ScopeExit.h"
39+
#include "llvm/ADT/StringRef.h"
3840
#include "llvm/Support/BuryPointer.h"
3941
#include "llvm/Support/ErrorHandling.h"
4042
#include "llvm/Support/FileSystem.h"
@@ -49,6 +51,135 @@ LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry)
4951

5052
namespace {
5153

54+
/// Dumps deserialized declarations.
55+
class DeserializedDeclsLineRangePrinter : public DelegatingDeserializationListener, public ASTConsumer {
56+
public:
57+
explicit DeserializedDeclsLineRangePrinter(SourceManager &SM, std::unique_ptr<llvm::raw_fd_ostream> OS)
58+
: DelegatingDeserializationListener(nullptr, false), SM(SM), OS(std::move(OS)) {}
59+
60+
void DeclRead(GlobalDeclID ID, const Decl *D) override {
61+
if (!IsCollectingDecls) {
62+
return;
63+
}
64+
if (!D || isa<TranslationUnitDecl>(D) || isa<LinkageSpecDecl>(D) ||
65+
isa<NamespaceDecl>(D))
66+
return;
67+
if (auto *DC = D->getDeclContext(); !DC || !DC->isFileContext())
68+
return;
69+
PendingDecls.push_back(D);
70+
DelegatingDeserializationListener::DeclRead(ID, D);
71+
}
72+
73+
using Position = std::pair<unsigned, unsigned>;
74+
struct RequiredRanges {
75+
StringRef Filename;
76+
std::vector<std::pair<Position, Position>> FromTo;
77+
};
78+
void HandleTranslationUnit(ASTContext &Context) override {
79+
IsCollectingDecls = false;
80+
std::vector<const Decl *> Decls = std::move(PendingDecls);
81+
if (!PendingDecls.empty()) {
82+
llvm::errs() << "Deserialized more decls while printing, total of "
83+
<< PendingDecls.size() << "\n";
84+
PendingDecls.clear();
85+
}
86+
87+
// Merge ranges in each of the files. For simplicity, track lines and hope
88+
// they do not break things.
89+
struct FileData {
90+
std::vector<std::pair<Position, Position>> FromTo;
91+
std::vector<std::pair<unsigned, unsigned>> Columns;
92+
OptionalFileEntryRef Ref;
93+
};
94+
llvm::DenseMap<const FileEntry *, FileData> FileToLines;
95+
for (const Decl *D : Decls) {
96+
CharSourceRange R = SM.getExpansionRange(D->getSourceRange());
97+
if (!R.isValid())
98+
continue;
99+
100+
auto *F = SM.getFileEntryForID(SM.getFileID(R.getBegin()));
101+
if (F != SM.getFileEntryForID(SM.getFileID(R.getEnd())))
102+
continue;
103+
104+
auto &Data = FileToLines[F];
105+
if (!Data.Ref)
106+
Data.Ref =
107+
SM.getFileEntryRefForID(SM.getFileID(R.getBegin()));
108+
Data.FromTo.push_back({{SM.getSpellingLineNumber(R.getBegin()), SM.getSpellingColumnNumber(R.getBegin())},
109+
{SM.getSpellingLineNumber(R.getEnd()), SM.getSpellingColumnNumber(R.getEnd())}});
110+
}
111+
112+
std::vector<RequiredRanges> Result;
113+
for (auto &[F, Data] : FileToLines) {
114+
auto& FromTo = Data.FromTo;
115+
assert(!FromTo.empty());
116+
117+
if (!Data.Ref) continue;
118+
119+
llvm::sort(FromTo);
120+
121+
std::vector<std::pair<Position, Position>> MergedLines;
122+
MergedLines.push_back(FromTo.front());
123+
for (auto It = FromTo.begin() + 1; It < FromTo.end(); ++It) {
124+
if (MergedLines.back().second < It->first) {
125+
MergedLines.push_back(*It);
126+
continue;
127+
}
128+
if (MergedLines.back().second < It->second)
129+
MergedLines.back().second = It->second;
130+
}
131+
Result.push_back({Data.Ref->getName(), MergedLines});
132+
}
133+
printJson(Result);
134+
}
135+
136+
void printJson(const std::vector<RequiredRanges>& Result) {
137+
*OS << "{\n";
138+
*OS << " \"required_ranges\": [\n";
139+
for (size_t i = 0; i < Result.size(); ++i) {
140+
auto &F = Result[i].Filename;
141+
auto &MergedLines = Result[i].FromTo;
142+
*OS << " {\n";
143+
*OS << " \"file\": \"" << F << "\",\n";
144+
*OS << " \"range\": [\n";
145+
for (size_t j = 0; j < MergedLines.size(); ++j) {
146+
auto &From = MergedLines[j].first;
147+
auto &To = MergedLines[j].second;
148+
*OS << " {\n";
149+
*OS << " \"from\": {\n";
150+
*OS << " \"line\": " << From.first << ",\n";
151+
*OS << " \"column\": " << From.second << "\n },\n";
152+
*OS << " \"to\": {\n";
153+
*OS << " \"line\": " << To.first << ",\n";
154+
*OS << " \"column\": " << To.second << "\n }\n";
155+
*OS << " }";
156+
if (j < MergedLines.size() - 1) {
157+
*OS << ",";
158+
}
159+
*OS << "\n";
160+
}
161+
*OS << " ]\n }";
162+
if (i < Result.size() - 1) {
163+
*OS << ",";
164+
}
165+
*OS << "\n";
166+
}
167+
*OS << " ]\n";
168+
*OS << "}\n";
169+
}
170+
171+
ASTDeserializationListener *GetASTDeserializationListener() override {
172+
return this;
173+
}
174+
175+
private:
176+
std::vector<const Decl *> PendingDecls;
177+
bool IsCollectingDecls = true;
178+
const SourceManager &SM;
179+
std::unique_ptr<llvm::raw_ostream> OS;
180+
};
181+
182+
52183
/// Dumps deserialized declarations.
53184
class DeserializedDeclsDumper : public DelegatingDeserializationListener {
54185
public:
@@ -121,6 +252,19 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
121252
if (!Consumer)
122253
return nullptr;
123254

255+
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
256+
llvm::StringRef PrintDeserializedDeclarationsPath = CI.getFrontendOpts().PrintDeserializedDeclarationsPath;
257+
if (!PrintDeserializedDeclarationsPath.empty()) {
258+
std::error_code ErrorCode;
259+
auto* FileStream = new llvm::raw_fd_ostream(PrintDeserializedDeclarationsPath, ErrorCode, llvm::sys::fs::OF_None);
260+
if (!ErrorCode) {
261+
DeserializedDeclsLineRangePrinter* Printer = new DeserializedDeclsLineRangePrinter(CI.getSourceManager(), std::unique_ptr<llvm::raw_fd_ostream>(FileStream));
262+
Consumers.push_back(std::unique_ptr<ASTConsumer>(Printer));
263+
} else {
264+
llvm::errs() << "Could not open file with path: " << PrintDeserializedDeclarationsPath << ", error: " << ErrorCode.message() << "\n";
265+
}
266+
}
267+
124268
// Validate -add-plugin args.
125269
bool FoundAllPlugins = true;
126270
for (const std::string &Arg : CI.getFrontendOpts().AddPluginActions) {
@@ -139,16 +283,17 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
139283
return nullptr;
140284

141285
// If there are no registered plugins we don't need to wrap the consumer
142-
if (FrontendPluginRegistry::begin() == FrontendPluginRegistry::end())
143-
return Consumer;
286+
if (FrontendPluginRegistry::begin() == FrontendPluginRegistry::end()) {
287+
Consumers.push_back(std::move(Consumer));
288+
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
289+
}
144290

145291
// If this is a code completion run, avoid invoking the plugin consumers
146292
if (CI.hasCodeCompletionConsumer())
147293
return Consumer;
148294

149295
// Collect the list of plugins that go before the main action (in Consumers)
150296
// or after it (in AfterConsumers)
151-
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
152297
std::vector<std::unique_ptr<ASTConsumer>> AfterConsumers;
153298
for (const FrontendPluginRegistry::entry &Plugin :
154299
FrontendPluginRegistry::entries()) {

0 commit comments

Comments
 (0)