1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "clang/Rewrite/Frontend/FrontendActions.h" |
10 | #include "clang/AST/ASTConsumer.h" |
11 | #include "clang/Basic/CharInfo.h" |
12 | #include "clang/Config/config.h" |
13 | #include "clang/Frontend/CompilerInstance.h" |
14 | #include "clang/Frontend/FrontendActions.h" |
15 | #include "clang/Frontend/FrontendDiagnostic.h" |
16 | #include "clang/Frontend/Utils.h" |
17 | #include "clang/Lex/Preprocessor.h" |
18 | #include "clang/Lex/PreprocessorOptions.h" |
19 | #include "clang/Rewrite/Frontend/ASTConsumers.h" |
20 | #include "clang/Rewrite/Frontend/FixItRewriter.h" |
21 | #include "clang/Rewrite/Frontend/Rewriters.h" |
22 | #include "clang/Serialization/ASTReader.h" |
23 | #include "clang/Serialization/Module.h" |
24 | #include "clang/Serialization/ModuleManager.h" |
25 | #include "llvm/ADT/DenseSet.h" |
26 | #include "llvm/Support/CrashRecoveryContext.h" |
27 | #include "llvm/Support/FileSystem.h" |
28 | #include "llvm/Support/Path.h" |
29 | #include "llvm/Support/raw_ostream.h" |
30 | #include <memory> |
31 | #include <utility> |
32 | |
33 | using namespace clang; |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | std::unique_ptr<ASTConsumer> |
40 | HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
41 | if (std::unique_ptr<raw_ostream> OS = |
42 | CI.createDefaultOutputFile(false, InFile)) |
43 | return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor()); |
44 | return nullptr; |
45 | } |
46 | |
47 | FixItAction::FixItAction() {} |
48 | FixItAction::~FixItAction() {} |
49 | |
50 | std::unique_ptr<ASTConsumer> |
51 | FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
52 | return llvm::make_unique<ASTConsumer>(); |
53 | } |
54 | |
55 | namespace { |
56 | class FixItRewriteInPlace : public FixItOptions { |
57 | public: |
58 | FixItRewriteInPlace() { InPlace = true; } |
59 | |
60 | std::string RewriteFilename(const std::string &Filename, int &fd) override { |
61 | llvm_unreachable("don't call RewriteFilename for inplace rewrites"); |
62 | } |
63 | }; |
64 | |
65 | class FixItActionSuffixInserter : public FixItOptions { |
66 | std::string NewSuffix; |
67 | |
68 | public: |
69 | FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan) |
70 | : NewSuffix(std::move(NewSuffix)) { |
71 | this->FixWhatYouCan = FixWhatYouCan; |
72 | } |
73 | |
74 | std::string RewriteFilename(const std::string &Filename, int &fd) override { |
75 | fd = -1; |
76 | SmallString<128> Path(Filename); |
77 | llvm::sys::path::replace_extension(Path, |
78 | NewSuffix + llvm::sys::path::extension(Path)); |
79 | return Path.str(); |
80 | } |
81 | }; |
82 | |
83 | class FixItRewriteToTemp : public FixItOptions { |
84 | public: |
85 | std::string RewriteFilename(const std::string &Filename, int &fd) override { |
86 | SmallString<128> Path; |
87 | llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename), |
88 | llvm::sys::path::extension(Filename).drop_front(), fd, |
89 | Path); |
90 | return Path.str(); |
91 | } |
92 | }; |
93 | } |
94 | |
95 | bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) { |
96 | const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); |
97 | if (!FEOpts.FixItSuffix.empty()) { |
98 | FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, |
99 | FEOpts.FixWhatYouCan)); |
100 | } else { |
101 | FixItOpts.reset(new FixItRewriteInPlace); |
102 | FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; |
103 | } |
104 | Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), |
105 | CI.getLangOpts(), FixItOpts.get())); |
106 | return true; |
107 | } |
108 | |
109 | void FixItAction::EndSourceFileAction() { |
110 | |
111 | Rewriter->WriteFixedFiles(); |
112 | } |
113 | |
114 | bool FixItRecompile::BeginInvocation(CompilerInstance &CI) { |
115 | |
116 | std::vector<std::pair<std::string, std::string> > RewrittenFiles; |
117 | bool err = false; |
118 | { |
119 | const FrontendOptions &FEOpts = CI.getFrontendOpts(); |
120 | std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction()); |
121 | if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) { |
122 | std::unique_ptr<FixItOptions> FixItOpts; |
123 | if (FEOpts.FixToTemporaries) |
124 | FixItOpts.reset(new FixItRewriteToTemp()); |
125 | else |
126 | FixItOpts.reset(new FixItRewriteInPlace()); |
127 | FixItOpts->Silent = true; |
128 | FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; |
129 | FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings; |
130 | FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(), |
131 | CI.getLangOpts(), FixItOpts.get()); |
132 | FixAction->Execute(); |
133 | |
134 | err = Rewriter.WriteFixedFiles(&RewrittenFiles); |
135 | |
136 | FixAction->EndSourceFile(); |
137 | CI.setSourceManager(nullptr); |
138 | CI.setFileManager(nullptr); |
139 | } else { |
140 | err = true; |
141 | } |
142 | } |
143 | if (err) |
144 | return false; |
145 | CI.getDiagnosticClient().clear(); |
146 | CI.getDiagnostics().Reset(); |
147 | |
148 | PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); |
149 | PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(), |
150 | RewrittenFiles.begin(), RewrittenFiles.end()); |
151 | PPOpts.RemappedFilesKeepOriginalName = false; |
152 | |
153 | return true; |
154 | } |
155 | |
156 | #if CLANG_ENABLE_OBJC_REWRITER |
157 | |
158 | std::unique_ptr<ASTConsumer> |
159 | RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { |
160 | if (std::unique_ptr<raw_ostream> OS = |
161 | CI.createDefaultOutputFile(false, InFile, "cpp")) { |
162 | if (CI.getLangOpts().ObjCRuntime.isNonFragile()) |
163 | return CreateModernObjCRewriter( |
164 | InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(), |
165 | CI.getDiagnosticOpts().NoRewriteMacros, |
166 | (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo)); |
167 | return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(), |
168 | CI.getLangOpts(), |
169 | CI.getDiagnosticOpts().NoRewriteMacros); |
170 | } |
171 | return nullptr; |
172 | } |
173 | |
174 | #endif |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | void RewriteMacrosAction::ExecuteAction() { |
181 | CompilerInstance &CI = getCompilerInstance(); |
182 | std::unique_ptr<raw_ostream> OS = |
183 | CI.createDefaultOutputFile(true, getCurrentFileOrBufferName()); |
184 | if (!OS) return; |
185 | |
186 | RewriteMacrosInInput(CI.getPreprocessor(), OS.get()); |
187 | } |
188 | |
189 | void RewriteTestAction::ExecuteAction() { |
190 | CompilerInstance &CI = getCompilerInstance(); |
191 | std::unique_ptr<raw_ostream> OS = |
192 | CI.createDefaultOutputFile(false, getCurrentFileOrBufferName()); |
193 | if (!OS) return; |
194 | |
195 | DoRewriteTest(CI.getPreprocessor(), OS.get()); |
196 | } |
197 | |
198 | class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener { |
199 | CompilerInstance &CI; |
200 | std::weak_ptr<raw_ostream> Out; |
201 | |
202 | llvm::DenseSet<const FileEntry*> Rewritten; |
203 | |
204 | public: |
205 | RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out) |
206 | : CI(CI), Out(Out) {} |
207 | |
208 | void visitModuleFile(StringRef Filename, |
209 | serialization::ModuleKind Kind) override { |
210 | auto *File = CI.getFileManager().getFile(Filename); |
211 | (0) . __assert_fail ("File && \"missing file for loaded module?\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/Rewrite/FrontendActions.cpp", 211, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(File && "missing file for loaded module?"); |
212 | |
213 | |
214 | if (!Rewritten.insert(File).second) |
215 | return; |
216 | |
217 | serialization::ModuleFile *MF = |
218 | CI.getModuleManager()->getModuleManager().lookup(File); |
219 | (0) . __assert_fail ("File && \"missing module file for loaded module?\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/Rewrite/FrontendActions.cpp", 219, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(File && "missing module file for loaded module?"); |
220 | |
221 | |
222 | if (!MF->isModule()) |
223 | return; |
224 | |
225 | auto OS = Out.lock(); |
226 | (0) . __assert_fail ("OS && \"loaded module file after finishing rewrite action?\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/Rewrite/FrontendActions.cpp", 226, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(OS && "loaded module file after finishing rewrite action?"); |
227 | |
228 | (*OS) << "#pragma clang module build "; |
229 | if (isValidIdentifier(MF->ModuleName)) |
230 | (*OS) << MF->ModuleName; |
231 | else { |
232 | (*OS) << '"'; |
233 | OS->write_escaped(MF->ModuleName); |
234 | (*OS) << '"'; |
235 | } |
236 | (*OS) << '\n'; |
237 | |
238 | |
239 | CompilerInstance Instance(CI.getPCHContainerOperations(), |
240 | &CI.getModuleCache()); |
241 | Instance.setInvocation( |
242 | std::make_shared<CompilerInvocation>(CI.getInvocation())); |
243 | Instance.createDiagnostics( |
244 | new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), |
245 | ); |
246 | Instance.getFrontendOpts().DisableFree = false; |
247 | Instance.getFrontendOpts().Inputs.clear(); |
248 | Instance.getFrontendOpts().Inputs.emplace_back( |
249 | Filename, InputKind(InputKind::Unknown, InputKind::Precompiled)); |
250 | Instance.getFrontendOpts().ModuleFiles.clear(); |
251 | Instance.getFrontendOpts().ModuleMapFiles.clear(); |
252 | |
253 | Instance.getPreprocessorOutputOpts().RewriteImports = false; |
254 | |
255 | llvm::CrashRecoveryContext().RunSafelyOnThread([&]() { |
256 | RewriteIncludesAction Action; |
257 | Action.OutputStream = OS; |
258 | Instance.ExecuteAction(Action); |
259 | }); |
260 | |
261 | (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n"; |
262 | } |
263 | }; |
264 | |
265 | bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) { |
266 | if (!OutputStream) { |
267 | OutputStream = |
268 | CI.createDefaultOutputFile(true, getCurrentFileOrBufferName()); |
269 | if (!OutputStream) |
270 | return false; |
271 | } |
272 | |
273 | auto &OS = *OutputStream; |
274 | |
275 | |
276 | |
277 | auto &Input = getCurrentInput(); |
278 | if (Input.getKind().getFormat() == InputKind::ModuleMap) { |
279 | if (Input.isFile()) { |
280 | OS << "# 1 \""; |
281 | OS.write_escaped(Input.getFile()); |
282 | OS << "\"\n"; |
283 | } |
284 | getCurrentModule()->print(OS); |
285 | OS << "#pragma clang module contents\n"; |
286 | } |
287 | |
288 | |
289 | |
290 | if (CI.getPreprocessorOutputOpts().RewriteImports) { |
291 | CI.createModuleManager(); |
292 | CI.getModuleManager()->addListener( |
293 | llvm::make_unique<RewriteImportsListener>(CI, OutputStream)); |
294 | } |
295 | |
296 | return true; |
297 | } |
298 | |
299 | void RewriteIncludesAction::ExecuteAction() { |
300 | CompilerInstance &CI = getCompilerInstance(); |
301 | |
302 | |
303 | |
304 | if (CI.getPreprocessorOutputOpts().RewriteImports) { |
305 | std::string Buffer; |
306 | llvm::raw_string_ostream OS(Buffer); |
307 | |
308 | RewriteIncludesInInput(CI.getPreprocessor(), &OS, |
309 | CI.getPreprocessorOutputOpts()); |
310 | |
311 | (*OutputStream) << OS.str(); |
312 | } else { |
313 | RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(), |
314 | CI.getPreprocessorOutputOpts()); |
315 | } |
316 | |
317 | OutputStream.reset(); |
318 | } |
319 | |