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,135 @@ LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry)
4951
5052namespace {
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.
53184class DeserializedDeclsDumper : public DelegatingDeserializationListener {
54185public:
@@ -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