[clang] [WIP] Implement `-dump-deserialized-declaration-ranges` flag. (PR #133910)
Viktoriia Bakalova via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 4 08:48:44 PDT 2025
================
@@ -49,6 +51,150 @@ LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry)
namespace {
+/// DeserializedDeclsLineRangePrinter dumps ranges of deserialized declarations
+/// to aid debugging and bug minimization. It implements ASTConsumer and
+/// ASTDeserializationListener, so that an object of
+/// DeserializedDeclsLineRangePrinter registers as its own listener. The
+/// ASTDeserializationListener interface provides the DeclRead callback that we
+/// use to collect the deserialized Decls. Note that printing or otherwise
+/// processing them as this point is dangerous, since that could trigger
+/// additional deserialization and crash compilation. Therefore, we process the
+/// collected Decls in HandleTranslationUnit method of ASTConsumer. This is a
+/// safe point, since we know that by this point all the Decls needed by the
+/// compiler frontend have been deserialized. In case our processing causes
+/// further deserialization, DeclRead from the listener might be called again.
+/// However, at that point we don't accept any more Decls for processing.
+class DeserializedDeclsLineRangePrinter : public ASTDeserializationListener,
+ public ASTConsumer {
+public:
+ explicit DeserializedDeclsLineRangePrinter(
+ SourceManager &SM, std::unique_ptr<llvm::raw_fd_ostream> OS)
+ : ASTDeserializationListener(), SM(SM), OS(std::move(OS)) {}
+
+ void DeclRead(GlobalDeclID ID, const Decl *D) override {
+ if (!IsCollectingDecls) {
+ return;
+ }
+ if (!D || isa<TranslationUnitDecl>(D) || isa<LinkageSpecDecl>(D) ||
+ isa<NamespaceDecl>(D))
+ return;
+ if (auto *DC = D->getDeclContext(); !DC || !DC->isFileContext())
+ return;
+ PendingDecls.push_back(D);
+ ASTDeserializationListener::DeclRead(ID, D);
+ }
+
+ using Position = std::pair<unsigned, unsigned>;
+ struct RequiredRanges {
+ StringRef Filename;
+ std::vector<std::pair<Position, Position>> FromTo;
+ };
+ void HandleTranslationUnit(ASTContext &Context) override {
+ IsCollectingDecls = false;
+ std::vector<const Decl *> Decls = std::move(PendingDecls);
+ if (!PendingDecls.empty()) {
+ llvm::errs() << "Deserialized more decls while printing, total of "
+ << PendingDecls.size() << "\n";
+ PendingDecls.clear();
+ }
+
+ // Merge ranges in each of the files. For simplicity, track lines and hope
+ // they do not break things.
+ struct FileData {
+ std::vector<std::pair<Position, Position>> FromTo;
+ std::vector<std::pair<unsigned, unsigned>> Columns;
+ OptionalFileEntryRef Ref;
+ };
+ llvm::DenseMap<const FileEntry *, FileData> FileToLines;
+ for (const Decl *D : Decls) {
+ CharSourceRange R = SM.getExpansionRange(D->getSourceRange());
+ if (!R.isValid())
+ continue;
+
+ auto *F = SM.getFileEntryForID(SM.getFileID(R.getBegin()));
+ if (F != SM.getFileEntryForID(SM.getFileID(R.getEnd())))
+ continue;
+
+ auto &Data = FileToLines[F];
+ if (!Data.Ref)
+ Data.Ref = SM.getFileEntryRefForID(SM.getFileID(R.getBegin()));
+ Data.FromTo.push_back({{SM.getSpellingLineNumber(R.getBegin()),
+ SM.getSpellingColumnNumber(R.getBegin())},
+ {SM.getSpellingLineNumber(R.getEnd()),
+ SM.getSpellingColumnNumber(R.getEnd())}});
+ }
+
+ std::vector<RequiredRanges> Result;
+ for (auto &[F, Data] : FileToLines) {
+ auto &FromTo = Data.FromTo;
+ assert(!FromTo.empty());
+
+ if (!Data.Ref)
+ continue;
+
+ llvm::sort(FromTo);
+
+ std::vector<std::pair<Position, Position>> MergedLines;
+ MergedLines.push_back(FromTo.front());
+ for (auto It = FromTo.begin() + 1; It < FromTo.end(); ++It) {
+ if (MergedLines.back().second < It->first) {
+ MergedLines.push_back(*It);
+ continue;
+ }
+ if (MergedLines.back().second < It->second)
+ MergedLines.back().second = It->second;
+ }
+ Result.push_back({Data.Ref->getName(), MergedLines});
+ }
+ printJson(Result);
+ }
+
+ void printJson(const std::vector<RequiredRanges> &Result) {
+ *OS << "{\n";
+ *OS << " \"required_ranges\": [\n";
+ for (size_t i = 0; i < Result.size(); ++i) {
+ auto &F = Result[i].Filename;
+ auto &MergedLines = Result[i].FromTo;
+ *OS << " {\n";
+ *OS << " \"file\": \"" << F << "\",\n";
+ *OS << " \"range\": [\n";
+ for (size_t j = 0; j < MergedLines.size(); ++j) {
+ auto &From = MergedLines[j].first;
+ auto &To = MergedLines[j].second;
+ *OS << " {\n";
+ *OS << " \"from\": {\n";
+ *OS << " \"line\": " << From.first << ",\n";
+ *OS << " \"column\": " << From.second << "\n },\n";
+ *OS << " \"to\": {\n";
+ *OS << " \"line\": " << To.first << ",\n";
+ *OS << " \"column\": " << To.second << "\n }\n";
+ *OS << " }";
+ if (j < MergedLines.size() - 1) {
+ *OS << ",";
+ }
+ *OS << "\n";
+ }
+ *OS << " ]\n }";
+ if (i < Result.size() - 1) {
+ *OS << ",";
----------------
VitaNuo wrote:
Done.
https://github.com/llvm/llvm-project/pull/133910
More information about the cfe-commits
mailing list