FrontendAction.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. //===--- FrontendAction.cpp -----------------------------------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/Frontend/FrontendAction.h"
  10. #include "clang/AST/ASTConsumer.h"
  11. #include "clang/AST/ASTContext.h"
  12. #include "clang/AST/DeclGroup.h"
  13. #include "clang/Frontend/ASTUnit.h"
  14. #include "clang/Frontend/CompilerInstance.h"
  15. #include "clang/Frontend/FrontendDiagnostic.h"
  16. #include "clang/Frontend/FrontendPluginRegistry.h"
  17. #include "clang/Frontend/LayoutOverrideSource.h"
  18. #include "clang/Frontend/MultiplexConsumer.h"
  19. #include "clang/Frontend/Utils.h"
  20. #include "clang/Lex/HeaderSearch.h"
  21. #include "clang/Lex/Preprocessor.h"
  22. #include "clang/Parse/ParseAST.h"
  23. #include "clang/Serialization/ASTDeserializationListener.h"
  24. #include "clang/Serialization/ASTReader.h"
  25. #include "clang/Serialization/GlobalModuleIndex.h"
  26. #include "llvm/Support/ErrorHandling.h"
  27. #include "llvm/Support/FileSystem.h"
  28. #include "llvm/Support/MemoryBuffer.h"
  29. #include "llvm/Support/Timer.h"
  30. #include "llvm/Support/raw_ostream.h"
  31. #include <system_error>
  32. using namespace clang;
  33. template class llvm::Registry<clang::PluginASTAction>;
  34. namespace {
  35. class DelegatingDeserializationListener : public ASTDeserializationListener {
  36. ASTDeserializationListener *Previous;
  37. bool DeletePrevious;
  38. public:
  39. explicit DelegatingDeserializationListener(
  40. ASTDeserializationListener *Previous, bool DeletePrevious)
  41. : Previous(Previous), DeletePrevious(DeletePrevious) {}
  42. virtual ~DelegatingDeserializationListener() {
  43. if (DeletePrevious)
  44. delete Previous;
  45. }
  46. void ReaderInitialized(ASTReader *Reader) override {
  47. if (Previous)
  48. Previous->ReaderInitialized(Reader);
  49. }
  50. void IdentifierRead(serialization::IdentID ID,
  51. IdentifierInfo *II) override {
  52. if (Previous)
  53. Previous->IdentifierRead(ID, II);
  54. }
  55. void TypeRead(serialization::TypeIdx Idx, QualType T) override {
  56. if (Previous)
  57. Previous->TypeRead(Idx, T);
  58. }
  59. void DeclRead(serialization::DeclID ID, const Decl *D) override {
  60. if (Previous)
  61. Previous->DeclRead(ID, D);
  62. }
  63. void SelectorRead(serialization::SelectorID ID, Selector Sel) override {
  64. if (Previous)
  65. Previous->SelectorRead(ID, Sel);
  66. }
  67. void MacroDefinitionRead(serialization::PreprocessedEntityID PPID,
  68. MacroDefinition *MD) override {
  69. if (Previous)
  70. Previous->MacroDefinitionRead(PPID, MD);
  71. }
  72. };
  73. /// \brief Dumps deserialized declarations.
  74. class DeserializedDeclsDumper : public DelegatingDeserializationListener {
  75. public:
  76. explicit DeserializedDeclsDumper(ASTDeserializationListener *Previous,
  77. bool DeletePrevious)
  78. : DelegatingDeserializationListener(Previous, DeletePrevious) {}
  79. void DeclRead(serialization::DeclID ID, const Decl *D) override {
  80. llvm::outs() << "PCH DECL: " << D->getDeclKindName();
  81. if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
  82. llvm::outs() << " - " << *ND;
  83. llvm::outs() << "\n";
  84. DelegatingDeserializationListener::DeclRead(ID, D);
  85. }
  86. };
  87. /// \brief Checks deserialized declarations and emits error if a name
  88. /// matches one given in command-line using -error-on-deserialized-decl.
  89. class DeserializedDeclsChecker : public DelegatingDeserializationListener {
  90. ASTContext &Ctx;
  91. std::set<std::string> NamesToCheck;
  92. public:
  93. DeserializedDeclsChecker(ASTContext &Ctx,
  94. const std::set<std::string> &NamesToCheck,
  95. ASTDeserializationListener *Previous,
  96. bool DeletePrevious)
  97. : DelegatingDeserializationListener(Previous, DeletePrevious), Ctx(Ctx),
  98. NamesToCheck(NamesToCheck) {}
  99. void DeclRead(serialization::DeclID ID, const Decl *D) override {
  100. if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
  101. if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
  102. unsigned DiagID
  103. = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
  104. "%0 was deserialized");
  105. Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
  106. << ND->getNameAsString();
  107. }
  108. DelegatingDeserializationListener::DeclRead(ID, D);
  109. }
  110. };
  111. } // end anonymous namespace
  112. FrontendAction::FrontendAction() : Instance(nullptr) {}
  113. FrontendAction::~FrontendAction() {}
  114. void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput,
  115. ASTUnit *AST) {
  116. this->CurrentInput = CurrentInput;
  117. CurrentASTUnit.reset(AST);
  118. }
  119. std::unique_ptr<ASTConsumer>
  120. FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
  121. StringRef InFile) {
  122. std::unique_ptr<ASTConsumer> Consumer = CreateASTConsumer(CI, InFile);
  123. if (!Consumer)
  124. return nullptr;
  125. if (CI.getFrontendOpts().AddPluginActions.size() == 0)
  126. return Consumer;
  127. // Make sure the non-plugin consumer is first, so that plugins can't
  128. // modifiy the AST.
  129. std::vector<std::unique_ptr<ASTConsumer>> Consumers;
  130. Consumers.push_back(std::move(Consumer));
  131. for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size();
  132. i != e; ++i) {
  133. // This is O(|plugins| * |add_plugins|), but since both numbers are
  134. // way below 50 in practice, that's ok.
  135. for (FrontendPluginRegistry::iterator
  136. it = FrontendPluginRegistry::begin(),
  137. ie = FrontendPluginRegistry::end();
  138. it != ie; ++it) {
  139. if (it->getName() != CI.getFrontendOpts().AddPluginActions[i])
  140. continue;
  141. std::unique_ptr<PluginASTAction> P = it->instantiate();
  142. if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
  143. Consumers.push_back(P->CreateASTConsumer(CI, InFile));
  144. }
  145. }
  146. return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
  147. }
  148. bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
  149. const FrontendInputFile &Input) {
  150. assert(!Instance && "Already processing a source file!");
  151. assert(!Input.isEmpty() && "Unexpected empty filename!");
  152. setCurrentInput(Input);
  153. setCompilerInstance(&CI);
  154. StringRef InputFile = Input.getFile();
  155. bool HasBegunSourceFile = false;
  156. if (!BeginInvocation(CI))
  157. goto failure;
  158. // AST files follow a very different path, since they share objects via the
  159. // AST unit.
  160. if (Input.getKind() == IK_AST) {
  161. assert(!usesPreprocessorOnly() &&
  162. "Attempt to pass AST file to preprocessor only action!");
  163. assert(hasASTFileSupport() &&
  164. "This action does not have AST file support!");
  165. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
  166. ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags,
  167. CI.getFileSystemOpts());
  168. if (!AST)
  169. goto failure;
  170. setCurrentInput(Input, AST);
  171. // Inform the diagnostic client we are processing a source file.
  172. CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr);
  173. HasBegunSourceFile = true;
  174. // Set the shared objects, these are reset when we finish processing the
  175. // file, otherwise the CompilerInstance will happily destroy them.
  176. CI.setFileManager(&AST->getFileManager());
  177. CI.setSourceManager(&AST->getSourceManager());
  178. CI.setPreprocessor(&AST->getPreprocessor());
  179. CI.setASTContext(&AST->getASTContext());
  180. // Initialize the action.
  181. if (!BeginSourceFileAction(CI, InputFile))
  182. goto failure;
  183. // Create the AST consumer.
  184. CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile));
  185. if (!CI.hasASTConsumer())
  186. goto failure;
  187. return true;
  188. }
  189. if (!CI.hasVirtualFileSystem()) {
  190. if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
  191. createVFSFromCompilerInvocation(CI.getInvocation(),
  192. CI.getDiagnostics()))
  193. CI.setVirtualFileSystem(VFS);
  194. else
  195. goto failure;
  196. }
  197. // Set up the file and source managers, if needed.
  198. if (!CI.hasFileManager())
  199. CI.createFileManager();
  200. if (!CI.hasSourceManager())
  201. CI.createSourceManager(CI.getFileManager());
  202. // IR files bypass the rest of initialization.
  203. if (Input.getKind() == IK_LLVM_IR) {
  204. assert(hasIRSupport() &&
  205. "This action does not have IR file support!");
  206. // Inform the diagnostic client we are processing a source file.
  207. CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr);
  208. HasBegunSourceFile = true;
  209. // Initialize the action.
  210. if (!BeginSourceFileAction(CI, InputFile))
  211. goto failure;
  212. // Initialize the main file entry.
  213. if (!CI.InitializeSourceManager(CurrentInput))
  214. goto failure;
  215. return true;
  216. }
  217. // If the implicit PCH include is actually a directory, rather than
  218. // a single file, search for a suitable PCH file in that directory.
  219. if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
  220. FileManager &FileMgr = CI.getFileManager();
  221. PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
  222. StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
  223. if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
  224. std::error_code EC;
  225. SmallString<128> DirNative;
  226. llvm::sys::path::native(PCHDir->getName(), DirNative);
  227. bool Found = false;
  228. for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
  229. Dir != DirEnd && !EC; Dir.increment(EC)) {
  230. // Check whether this is an acceptable AST file.
  231. if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr,
  232. CI.getLangOpts(),
  233. CI.getTargetOpts(),
  234. CI.getPreprocessorOpts())) {
  235. PPOpts.ImplicitPCHInclude = Dir->path();
  236. Found = true;
  237. break;
  238. }
  239. }
  240. if (!Found) {
  241. CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude;
  242. return true;
  243. }
  244. }
  245. }
  246. // Set up the preprocessor.
  247. CI.createPreprocessor(getTranslationUnitKind());
  248. // Inform the diagnostic client we are processing a source file.
  249. CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
  250. &CI.getPreprocessor());
  251. HasBegunSourceFile = true;
  252. // Initialize the action.
  253. if (!BeginSourceFileAction(CI, InputFile))
  254. goto failure;
  255. // Initialize the main file entry. It is important that this occurs after
  256. // BeginSourceFileAction, which may change CurrentInput during module builds.
  257. if (!CI.InitializeSourceManager(CurrentInput))
  258. goto failure;
  259. // Create the AST context and consumer unless this is a preprocessor only
  260. // action.
  261. if (!usesPreprocessorOnly()) {
  262. CI.createASTContext();
  263. std::unique_ptr<ASTConsumer> Consumer =
  264. CreateWrappedASTConsumer(CI, InputFile);
  265. if (!Consumer)
  266. goto failure;
  267. CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
  268. if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
  269. // Convert headers to PCH and chain them.
  270. IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader;
  271. source = createChainedIncludesSource(CI, FinalReader);
  272. if (!source)
  273. goto failure;
  274. CI.setModuleManager(static_cast<ASTReader *>(FinalReader.get()));
  275. CI.getASTContext().setExternalSource(source);
  276. } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
  277. // Use PCH.
  278. assert(hasPCHSupport() && "This action does not have PCH support!");
  279. ASTDeserializationListener *DeserialListener =
  280. Consumer->GetASTDeserializationListener();
  281. bool DeleteDeserialListener = false;
  282. if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) {
  283. DeserialListener = new DeserializedDeclsDumper(DeserialListener,
  284. DeleteDeserialListener);
  285. DeleteDeserialListener = true;
  286. }
  287. if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) {
  288. DeserialListener = new DeserializedDeclsChecker(
  289. CI.getASTContext(),
  290. CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
  291. DeserialListener, DeleteDeserialListener);
  292. DeleteDeserialListener = true;
  293. }
  294. CI.createPCHExternalASTSource(
  295. CI.getPreprocessorOpts().ImplicitPCHInclude,
  296. CI.getPreprocessorOpts().DisablePCHValidation,
  297. CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener,
  298. DeleteDeserialListener);
  299. if (!CI.getASTContext().getExternalSource())
  300. goto failure;
  301. }
  302. CI.setASTConsumer(std::move(Consumer));
  303. if (!CI.hasASTConsumer())
  304. goto failure;
  305. }
  306. // Initialize built-in info as long as we aren't using an external AST
  307. // source.
  308. if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
  309. Preprocessor &PP = CI.getPreprocessor();
  310. // If modules are enabled, create the module manager before creating
  311. // any builtins, so that all declarations know that they might be
  312. // extended by an external source.
  313. if (CI.getLangOpts().Modules)
  314. CI.createModuleManager();
  315. PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
  316. PP.getLangOpts());
  317. } else {
  318. // FIXME: If this is a problem, recover from it by creating a multiplex
  319. // source.
  320. assert((!CI.getLangOpts().Modules || CI.getModuleManager()) &&
  321. "modules enabled but created an external source that "
  322. "doesn't support modules");
  323. }
  324. // If there is a layout overrides file, attach an external AST source that
  325. // provides the layouts from that file.
  326. if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
  327. CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
  328. IntrusiveRefCntPtr<ExternalASTSource>
  329. Override(new LayoutOverrideSource(
  330. CI.getFrontendOpts().OverrideRecordLayoutsFile));
  331. CI.getASTContext().setExternalSource(Override);
  332. }
  333. return true;
  334. // If we failed, reset state since the client will not end up calling the
  335. // matching EndSourceFile().
  336. failure:
  337. if (isCurrentFileAST()) {
  338. CI.setASTContext(nullptr);
  339. CI.setPreprocessor(nullptr);
  340. CI.setSourceManager(nullptr);
  341. CI.setFileManager(nullptr);
  342. }
  343. if (HasBegunSourceFile)
  344. CI.getDiagnosticClient().EndSourceFile();
  345. CI.clearOutputFiles(/*EraseFiles=*/true);
  346. setCurrentInput(FrontendInputFile());
  347. setCompilerInstance(nullptr);
  348. return false;
  349. }
  350. bool FrontendAction::Execute() {
  351. CompilerInstance &CI = getCompilerInstance();
  352. if (CI.hasFrontendTimer()) {
  353. llvm::TimeRegion Timer(CI.getFrontendTimer());
  354. ExecuteAction();
  355. }
  356. else ExecuteAction();
  357. // If we are supposed to rebuild the global module index, do so now unless
  358. // there were any module-build failures.
  359. if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() &&
  360. CI.hasPreprocessor()) {
  361. GlobalModuleIndex::writeIndex(
  362. CI.getFileManager(),
  363. CI.getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
  364. }
  365. return true;
  366. }
  367. void FrontendAction::EndSourceFile() {
  368. CompilerInstance &CI = getCompilerInstance();
  369. // Inform the diagnostic client we are done with this source file.
  370. CI.getDiagnosticClient().EndSourceFile();
  371. // Finalize the action.
  372. EndSourceFileAction();
  373. // Sema references the ast consumer, so reset sema first.
  374. //
  375. // FIXME: There is more per-file stuff we could just drop here?
  376. bool DisableFree = CI.getFrontendOpts().DisableFree;
  377. if (DisableFree) {
  378. if (!isCurrentFileAST()) {
  379. CI.resetAndLeakSema();
  380. CI.resetAndLeakASTContext();
  381. }
  382. BuryPointer(CI.takeASTConsumer().get());
  383. } else {
  384. if (!isCurrentFileAST()) {
  385. CI.setSema(nullptr);
  386. CI.setASTContext(nullptr);
  387. }
  388. CI.setASTConsumer(nullptr);
  389. }
  390. // Inform the preprocessor we are done.
  391. if (CI.hasPreprocessor())
  392. CI.getPreprocessor().EndSourceFile();
  393. if (CI.getFrontendOpts().ShowStats) {
  394. llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
  395. CI.getPreprocessor().PrintStats();
  396. CI.getPreprocessor().getIdentifierTable().PrintStats();
  397. CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
  398. CI.getSourceManager().PrintStats();
  399. llvm::errs() << "\n";
  400. }
  401. // Cleanup the output streams, and erase the output files if instructed by the
  402. // FrontendAction.
  403. CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles());
  404. // FIXME: Only do this if DisableFree is set.
  405. if (isCurrentFileAST()) {
  406. CI.resetAndLeakSema();
  407. CI.resetAndLeakASTContext();
  408. CI.resetAndLeakPreprocessor();
  409. CI.resetAndLeakSourceManager();
  410. CI.resetAndLeakFileManager();
  411. }
  412. setCompilerInstance(nullptr);
  413. setCurrentInput(FrontendInputFile());
  414. }
  415. bool FrontendAction::shouldEraseOutputFiles() {
  416. return getCompilerInstance().getDiagnostics().hasErrorOccurred();
  417. }
  418. //===----------------------------------------------------------------------===//
  419. // Utility Actions
  420. //===----------------------------------------------------------------------===//
  421. void ASTFrontendAction::ExecuteAction() {
  422. CompilerInstance &CI = getCompilerInstance();
  423. if (!CI.hasPreprocessor())
  424. return;
  425. // FIXME: Move the truncation aspect of this into Sema, we delayed this till
  426. // here so the source manager would be initialized.
  427. if (hasCodeCompletionSupport() &&
  428. !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
  429. CI.createCodeCompletionConsumer();
  430. // Use a code completion consumer?
  431. CodeCompleteConsumer *CompletionConsumer = nullptr;
  432. if (CI.hasCodeCompletionConsumer())
  433. CompletionConsumer = &CI.getCodeCompletionConsumer();
  434. if (!CI.hasSema())
  435. CI.createSema(getTranslationUnitKind(), CompletionConsumer);
  436. ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
  437. CI.getFrontendOpts().SkipFunctionBodies);
  438. }
  439. void PluginASTAction::anchor() { }
  440. std::unique_ptr<ASTConsumer>
  441. PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
  442. StringRef InFile) {
  443. llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
  444. }
  445. std::unique_ptr<ASTConsumer>
  446. WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
  447. StringRef InFile) {
  448. return WrappedAction->CreateASTConsumer(CI, InFile);
  449. }
  450. bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
  451. return WrappedAction->BeginInvocation(CI);
  452. }
  453. bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
  454. StringRef Filename) {
  455. WrappedAction->setCurrentInput(getCurrentInput());
  456. WrappedAction->setCompilerInstance(&CI);
  457. return WrappedAction->BeginSourceFileAction(CI, Filename);
  458. }
  459. void WrapperFrontendAction::ExecuteAction() {
  460. WrappedAction->ExecuteAction();
  461. }
  462. void WrapperFrontendAction::EndSourceFileAction() {
  463. WrappedAction->EndSourceFileAction();
  464. }
  465. bool WrapperFrontendAction::usesPreprocessorOnly() const {
  466. return WrappedAction->usesPreprocessorOnly();
  467. }
  468. TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() {
  469. return WrappedAction->getTranslationUnitKind();
  470. }
  471. bool WrapperFrontendAction::hasPCHSupport() const {
  472. return WrappedAction->hasPCHSupport();
  473. }
  474. bool WrapperFrontendAction::hasASTFileSupport() const {
  475. return WrappedAction->hasASTFileSupport();
  476. }
  477. bool WrapperFrontendAction::hasIRSupport() const {
  478. return WrappedAction->hasIRSupport();
  479. }
  480. bool WrapperFrontendAction::hasCodeCompletionSupport() const {
  481. return WrappedAction->hasCodeCompletionSupport();
  482. }
  483. WrapperFrontendAction::WrapperFrontendAction(FrontendAction *WrappedAction)
  484. : WrappedAction(WrappedAction) {}