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"
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,144 @@ LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry)
4951
5052namespace {
5153
54+ // / DeserializedDeclsLineRangePrinter dumps ranges of deserialized declarations to aid debugging and bug minimization.
55+ // / It implements ASTConsumer and ASTDeserializationListener, so that an object of DeserializedDeclsLineRangePrinter registers
56+ // / as its own listener.
57+ // / The ASTDeserializationListener interface provides the DeclRead callback that we use to collect the deserialized Decls.
58+ // / Note that printing or otherwise processing them as this point is dangerous, since that could trigger additional
59+ // / deserialization and crash compilation.
60+ // / Therefore, we process the collected Decls in HandleTranslationUnit method of ASTConsumer.
61+ // / This is a safe point, since we know that by this point all the Decls needed by the compiler frontend have been
62+ // / deserialized. In case our processing causes further deserialization, DeclRead from the listener might be called again.
63+ // / However, at that point we don't accept any more Decls for processing.
64+ class DeserializedDeclsLineRangePrinter : public ASTDeserializationListener , public ASTConsumer {
65+ public:
66+ explicit DeserializedDeclsLineRangePrinter (SourceManager &SM, std::unique_ptr<llvm::raw_fd_ostream> OS)
67+ : ASTDeserializationListener(), SM(SM), OS(std::move(OS)) {}
68+
69+ void DeclRead (GlobalDeclID ID, const Decl *D) override {
70+ if (!IsCollectingDecls) {
71+ return ;
72+ }
73+ if (!D || isa<TranslationUnitDecl>(D) || isa<LinkageSpecDecl>(D) ||
74+ isa<NamespaceDecl>(D))
75+ return ;
76+ if (auto *DC = D->getDeclContext (); !DC || !DC->isFileContext ())
77+ return ;
78+ PendingDecls.push_back (D);
79+ ASTDeserializationListener::DeclRead (ID, D);
80+ }
81+
82+ using Position = std::pair<unsigned , unsigned >;
83+ struct RequiredRanges {
84+ StringRef Filename;
85+ std::vector<std::pair<Position, Position>> FromTo;
86+ };
87+ void HandleTranslationUnit (ASTContext &Context) override {
88+ IsCollectingDecls = false ;
89+ std::vector<const Decl *> Decls = std::move (PendingDecls);
90+ if (!PendingDecls.empty ()) {
91+ llvm::errs () << " Deserialized more decls while printing, total of "
92+ << PendingDecls.size () << " \n " ;
93+ PendingDecls.clear ();
94+ }
95+
96+ // Merge ranges in each of the files. For simplicity, track lines and hope
97+ // they do not break things.
98+ struct FileData {
99+ std::vector<std::pair<Position, Position>> FromTo;
100+ std::vector<std::pair<unsigned , unsigned >> Columns;
101+ OptionalFileEntryRef Ref;
102+ };
103+ llvm::DenseMap<const FileEntry *, FileData> FileToLines;
104+ for (const Decl *D : Decls) {
105+ CharSourceRange R = SM.getExpansionRange (D->getSourceRange ());
106+ if (!R.isValid ())
107+ continue ;
108+
109+ auto *F = SM.getFileEntryForID (SM.getFileID (R.getBegin ()));
110+ if (F != SM.getFileEntryForID (SM.getFileID (R.getEnd ())))
111+ continue ;
112+
113+ auto &Data = FileToLines[F];
114+ if (!Data.Ref )
115+ Data.Ref =
116+ SM.getFileEntryRefForID (SM.getFileID (R.getBegin ()));
117+ Data.FromTo .push_back ({{SM.getSpellingLineNumber (R.getBegin ()), SM.getSpellingColumnNumber (R.getBegin ())},
118+ {SM.getSpellingLineNumber (R.getEnd ()), SM.getSpellingColumnNumber (R.getEnd ())}});
119+ }
120+
121+ std::vector<RequiredRanges> Result;
122+ for (auto &[F, Data] : FileToLines) {
123+ auto & FromTo = Data.FromTo ;
124+ assert (!FromTo.empty ());
125+
126+ if (!Data.Ref ) continue ;
127+
128+ llvm::sort (FromTo);
129+
130+ std::vector<std::pair<Position, Position>> MergedLines;
131+ MergedLines.push_back (FromTo.front ());
132+ for (auto It = FromTo.begin () + 1 ; It < FromTo.end (); ++It) {
133+ if (MergedLines.back ().second < It->first ) {
134+ MergedLines.push_back (*It);
135+ continue ;
136+ }
137+ if (MergedLines.back ().second < It->second )
138+ MergedLines.back ().second = It->second ;
139+ }
140+ Result.push_back ({Data.Ref ->getName (), MergedLines});
141+ }
142+ printJson (Result);
143+ }
144+
145+ void printJson (const std::vector<RequiredRanges>& Result) {
146+ *OS << " {\n " ;
147+ *OS << " \" required_ranges\" : [\n " ;
148+ for (size_t i = 0 ; i < Result.size (); ++i) {
149+ auto &F = Result[i].Filename ;
150+ auto &MergedLines = Result[i].FromTo ;
151+ *OS << " {\n " ;
152+ *OS << " \" file\" : \" " << F << " \" ,\n " ;
153+ *OS << " \" range\" : [\n " ;
154+ for (size_t j = 0 ; j < MergedLines.size (); ++j) {
155+ auto &From = MergedLines[j].first ;
156+ auto &To = MergedLines[j].second ;
157+ *OS << " {\n " ;
158+ *OS << " \" from\" : {\n " ;
159+ *OS << " \" line\" : " << From.first << " ,\n " ;
160+ *OS << " \" column\" : " << From.second << " \n },\n " ;
161+ *OS << " \" to\" : {\n " ;
162+ *OS << " \" line\" : " << To.first << " ,\n " ;
163+ *OS << " \" column\" : " << To.second << " \n }\n " ;
164+ *OS << " }" ;
165+ if (j < MergedLines.size () - 1 ) {
166+ *OS << " ," ;
167+ }
168+ *OS << " \n " ;
169+ }
170+ *OS << " ]\n }" ;
171+ if (i < Result.size () - 1 ) {
172+ *OS << " ," ;
173+ }
174+ *OS << " \n " ;
175+ }
176+ *OS << " ]\n " ;
177+ *OS << " }\n " ;
178+ }
179+
180+ ASTDeserializationListener *GetASTDeserializationListener () override {
181+ return this ;
182+ }
183+
184+ private:
185+ std::vector<const Decl *> PendingDecls;
186+ bool IsCollectingDecls = true ;
187+ const SourceManager &SM;
188+ std::unique_ptr<llvm::raw_ostream> OS;
189+ };
190+
191+
52192// / Dumps deserialized declarations.
53193class DeserializedDeclsDumper : public DelegatingDeserializationListener {
54194public:
@@ -121,6 +261,19 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
121261 if (!Consumer)
122262 return nullptr ;
123263
264+ std::vector<std::unique_ptr<ASTConsumer>> Consumers;
265+ llvm::StringRef DumpDeserializedDeclarationRangesPath = CI.getFrontendOpts ().DumpDeserializedDeclarationRangesPath ;
266+ if (!DumpDeserializedDeclarationRangesPath.empty ()) {
267+ std::error_code ErrorCode;
268+ auto FileStream = std::make_unique<llvm::raw_fd_ostream>(DumpDeserializedDeclarationRangesPath, ErrorCode, llvm::sys::fs::OF_None);
269+ if (!ErrorCode) {
270+ auto Printer = std::make_unique<DeserializedDeclsLineRangePrinter>(CI.getSourceManager (), std::move (FileStream));
271+ Consumers.push_back (std::move (Printer));
272+ } else {
273+ llvm::errs () << " Failed to create output file for -dump-deserialized-declaration-ranges flag, file path: " << DumpDeserializedDeclarationRangesPath << " , error: " << ErrorCode.message () << " \n " ;
274+ }
275+ }
276+
124277 // Validate -add-plugin args.
125278 bool FoundAllPlugins = true ;
126279 for (const std::string &Arg : CI.getFrontendOpts ().AddPluginActions ) {
@@ -138,17 +291,12 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
138291 if (!FoundAllPlugins)
139292 return nullptr ;
140293
141- // If there are no registered plugins we don't need to wrap the consumer
142- if (FrontendPluginRegistry::begin () == FrontendPluginRegistry::end ())
143- return Consumer;
144-
145294 // If this is a code completion run, avoid invoking the plugin consumers
146295 if (CI.hasCodeCompletionConsumer ())
147296 return Consumer;
148297
149298 // Collect the list of plugins that go before the main action (in Consumers)
150299 // or after it (in AfterConsumers)
151- std::vector<std::unique_ptr<ASTConsumer>> Consumers;
152300 std::vector<std::unique_ptr<ASTConsumer>> AfterConsumers;
153301 for (const FrontendPluginRegistry::entry &Plugin :
154302 FrontendPluginRegistry::entries ()) {
@@ -191,6 +339,9 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
191339 Consumers.push_back (std::move (C));
192340 }
193341
342+ assert (Consumers.size () >= 1 && " should have added the main consumer" );
343+ if (Consumers.size () == 1 )
344+ return std::move (Consumers.front ());
194345 return std::make_unique<MultiplexConsumer>(std::move (Consumers));
195346}
196347
0 commit comments