mirror of
https://github.com/intel/llvm.git
synced 2026-01-25 19:44:38 +08:00
clang-cc: Switch to using FrontendAction. Whee.
Please report any discrepancies you see in clang-cc, I'm not confident that our regression tests cover all the fun ways one can use clang-cc. llvm-svn: 88776
This commit is contained in:
@@ -8,50 +8,32 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility may be invoked in the following manner:
|
||||
// clang --help - Output help info.
|
||||
// clang [options] - Read from stdin.
|
||||
// clang [options] file - Read from "file".
|
||||
// clang [options] file1 file2 - Read these files.
|
||||
// clang-cc --help - Output help info.
|
||||
// clang-cc [options] - Read from stdin.
|
||||
// clang-cc [options] file - Read from "file".
|
||||
// clang-cc [options] file1 file2 - Read these files.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Options.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/CodeGen/ModuleBuilder.h"
|
||||
#include "clang/Frontend/ASTConsumers.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/AnalysisConsumer.h"
|
||||
#include "clang/Frontend/CommandLineSourceLoc.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/DependencyOutputOptions.h"
|
||||
#include "clang/Frontend/FixItRewriter.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/PathDiagnosticClients.h"
|
||||
#include "clang/Frontend/PreprocessorOptions.h"
|
||||
#include "clang/Frontend/PreprocessorOutputOptions.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "clang/Frontend/VerifyDiagnosticsClient.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "clang/Parse/Parser.h"
|
||||
#include "clang/Sema/CodeCompleteConsumer.h"
|
||||
#include "clang/Sema/ParseAST.h"
|
||||
#include "clang/Sema/SemaDiagnostic.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
@@ -183,19 +165,6 @@ std::string GetBuiltinIncludePath(const char *Argv0) {
|
||||
return P.str();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic Parser driver
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void ParseFile(Preprocessor &PP, MinimalAction *PA) {
|
||||
Parser P(PP, *PA);
|
||||
PP.EnterMainSourceFile();
|
||||
|
||||
// Parsing the specified input file.
|
||||
P.ParseTranslationUnit();
|
||||
delete PA;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Main driver
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -205,359 +174,37 @@ static void ParseFile(Preprocessor &PP, MinimalAction *PA) {
|
||||
/// anything.
|
||||
llvm::Timer *ClangFrontendTimer = 0;
|
||||
|
||||
/// AddFixItLocations - Add any individual user specified "fix-it" locations,
|
||||
/// and return true on success.
|
||||
static bool AddFixItLocations(CompilerInstance &CI,
|
||||
FixItRewriter &FixItRewrite) {
|
||||
const std::vector<ParsedSourceLocation> &Locs =
|
||||
CI.getFrontendOpts().FixItLocations;
|
||||
for (unsigned i = 0, e = Locs.size(); i != e; ++i) {
|
||||
const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName);
|
||||
if (!File) {
|
||||
CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file)
|
||||
<< Locs[i].FileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
RequestedSourceLocation Requested;
|
||||
Requested.File = File;
|
||||
Requested.Line = Locs[i].Line;
|
||||
Requested.Column = Locs[i].Column;
|
||||
FixItRewrite.addFixItLocation(Requested);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ASTConsumer *CreateConsumerAction(CompilerInstance &CI,
|
||||
Preprocessor &PP,
|
||||
const std::string &InFile,
|
||||
ProgActions PA) {
|
||||
const FrontendOptions &FEOpts = CI.getFrontendOpts();
|
||||
|
||||
static FrontendAction *CreateFrontendAction(ProgActions PA) {
|
||||
switch (PA) {
|
||||
default:
|
||||
return 0;
|
||||
|
||||
case ASTPrint:
|
||||
return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile));
|
||||
|
||||
case ASTPrintXML:
|
||||
return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile,
|
||||
"xml"));
|
||||
|
||||
case ASTDump:
|
||||
return CreateASTDumper();
|
||||
|
||||
case ASTView:
|
||||
return CreateASTViewer();
|
||||
|
||||
case DumpRecordLayouts:
|
||||
return CreateRecordLayoutDumper();
|
||||
|
||||
case InheritanceView:
|
||||
return CreateInheritanceViewer(FEOpts.ViewClassInheritance);
|
||||
|
||||
case EmitAssembly:
|
||||
case EmitLLVM:
|
||||
case EmitBC:
|
||||
case EmitLLVMOnly: {
|
||||
BackendAction Act;
|
||||
llvm::OwningPtr<llvm::raw_ostream> OS;
|
||||
if (ProgAction == EmitAssembly) {
|
||||
Act = Backend_EmitAssembly;
|
||||
OS.reset(CI.createDefaultOutputFile(false, InFile, "s"));
|
||||
} else if (ProgAction == EmitLLVM) {
|
||||
Act = Backend_EmitLL;
|
||||
OS.reset(CI.createDefaultOutputFile(false, InFile, "ll"));
|
||||
} else if (ProgAction == EmitLLVMOnly) {
|
||||
Act = Backend_EmitNothing;
|
||||
} else {
|
||||
Act = Backend_EmitBC;
|
||||
OS.reset(CI.createDefaultOutputFile(true, InFile, "bc"));
|
||||
}
|
||||
|
||||
return CreateBackendConsumer(Act, PP.getDiagnostics(), PP.getLangOptions(),
|
||||
CI.getCodeGenOpts(), InFile, OS.take(),
|
||||
CI.getLLVMContext());
|
||||
default: return 0;
|
||||
case ASTDump: return new ASTDumpAction();
|
||||
case ASTPrint: return new ASTPrintAction();
|
||||
case ASTPrintXML: return new ASTPrintXMLAction();
|
||||
case ASTView: return new ASTViewAction();
|
||||
case DumpRawTokens: return new DumpRawTokensAction();
|
||||
case DumpRecordLayouts: return new DumpRecordAction();
|
||||
case DumpTokens: return new DumpTokensAction();
|
||||
case EmitAssembly: return new EmitAssemblyAction();
|
||||
case EmitBC: return new EmitBCAction();
|
||||
case EmitHTML: return new HTMLPrintAction();
|
||||
case EmitLLVM: return new EmitLLVMAction();
|
||||
case EmitLLVMOnly: return new EmitLLVMOnlyAction();
|
||||
case FixIt: return new FixItAction();
|
||||
case GeneratePCH: return new GeneratePCHAction();
|
||||
case GeneratePTH: return new GeneratePTHAction();
|
||||
case InheritanceView: return new InheritanceViewAction();
|
||||
case ParseNoop: return new ParseOnlyAction();
|
||||
case ParsePrintCallbacks: return new PrintParseAction();
|
||||
case ParseSyntaxOnly: return new SyntaxOnlyAction();
|
||||
case PrintDeclContext: return new DeclContextPrintAction();
|
||||
case PrintPreprocessedInput: return new PrintPreprocessedAction();
|
||||
case RewriteBlocks: return new RewriteBlocksAction();
|
||||
case RewriteMacros: return new RewriteMacrosAction();
|
||||
case RewriteObjC: return new RewriteObjCAction();
|
||||
case RewriteTest: return new RewriteTestAction();
|
||||
case RunAnalysis: return new AnalysisAction();
|
||||
case RunPreprocessorOnly: return new PreprocessOnlyAction();
|
||||
}
|
||||
|
||||
case RewriteObjC:
|
||||
return CreateObjCRewriter(InFile,
|
||||
CI.createDefaultOutputFile(true, InFile, "cpp"),
|
||||
PP.getDiagnostics(), PP.getLangOptions(),
|
||||
CI.getDiagnosticOpts().NoRewriteMacros);
|
||||
|
||||
case RewriteBlocks:
|
||||
return CreateBlockRewriter(InFile, PP.getDiagnostics(),
|
||||
PP.getLangOptions());
|
||||
|
||||
case FixIt:
|
||||
return new ASTConsumer();
|
||||
|
||||
case ParseSyntaxOnly:
|
||||
return new ASTConsumer();
|
||||
|
||||
case PrintDeclContext:
|
||||
return CreateDeclContextPrinter();
|
||||
}
|
||||
}
|
||||
|
||||
/// ProcessInputFile - Process a single input file with the specified state.
|
||||
static void ProcessInputFile(CompilerInstance &CI, const std::string &InFile,
|
||||
ProgActions PA) {
|
||||
Preprocessor &PP = CI.getPreprocessor();
|
||||
const FrontendOptions &FEOpts = CI.getFrontendOpts();
|
||||
llvm::OwningPtr<ASTConsumer> Consumer;
|
||||
llvm::OwningPtr<FixItRewriter> FixItRewrite;
|
||||
bool CompleteTranslationUnit = true;
|
||||
|
||||
switch (PA) {
|
||||
default:
|
||||
Consumer.reset(CreateConsumerAction(CI, PP, InFile, PA));
|
||||
if (!Consumer.get()) {
|
||||
PP.getDiagnostics().Report(diag::err_fe_invalid_ast_action);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case EmitHTML:
|
||||
Consumer.reset(CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile),
|
||||
PP));
|
||||
break;
|
||||
|
||||
case RunAnalysis:
|
||||
Consumer.reset(CreateAnalysisConsumer(PP, FEOpts.OutputFile,
|
||||
CI.getAnalyzerOpts()));
|
||||
break;
|
||||
|
||||
case GeneratePCH: {
|
||||
const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
|
||||
bool Relocatable = FEOpts.RelocatablePCH;
|
||||
if (Relocatable && Sysroot.empty()) {
|
||||
PP.Diag(SourceLocation(), diag::err_relocatable_without_without_isysroot);
|
||||
Relocatable = false;
|
||||
}
|
||||
|
||||
llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
|
||||
if (Relocatable)
|
||||
Consumer.reset(CreatePCHGenerator(PP, OS, Sysroot.c_str()));
|
||||
else
|
||||
Consumer.reset(CreatePCHGenerator(PP, OS));
|
||||
CompleteTranslationUnit = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Do any necessary set up for non-consumer actions.
|
||||
case DumpRawTokens:
|
||||
case DumpTokens:
|
||||
case RunPreprocessorOnly:
|
||||
case ParseNoop:
|
||||
case GeneratePTH:
|
||||
case PrintPreprocessedInput:
|
||||
case ParsePrintCallbacks:
|
||||
case RewriteMacros:
|
||||
case RewriteTest:
|
||||
break; // No setup.
|
||||
}
|
||||
|
||||
// Check if we want a fix-it rewriter.
|
||||
if (PA == FixIt) {
|
||||
FixItRewrite.reset(new FixItRewriter(PP.getDiagnostics(),
|
||||
PP.getSourceManager(),
|
||||
PP.getLangOptions()));
|
||||
if (!AddFixItLocations(CI, *FixItRewrite))
|
||||
return;
|
||||
}
|
||||
|
||||
if (Consumer) {
|
||||
// Create the ASTContext.
|
||||
CI.createASTContext();
|
||||
|
||||
// Create the external AST source when using PCH.
|
||||
const std::string &ImplicitPCHInclude =
|
||||
CI.getPreprocessorOpts().getImplicitPCHInclude();
|
||||
if (!ImplicitPCHInclude.empty()) {
|
||||
CI.createPCHExternalASTSource(ImplicitPCHInclude);
|
||||
if (!CI.getASTContext().getExternalSource())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize builtin info as long as we aren't using an external AST
|
||||
// source.
|
||||
if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource())
|
||||
PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
|
||||
PP.getLangOptions().NoBuiltin);
|
||||
|
||||
// Initialize the main file entry. This needs to be delayed until after PCH
|
||||
// has loaded.
|
||||
if (!CI.InitializeSourceManager(InFile))
|
||||
return;
|
||||
|
||||
if (Consumer) {
|
||||
// FIXME: Move the truncation aspect of this into Sema.
|
||||
if (!FEOpts.CodeCompletionAt.FileName.empty())
|
||||
CI.createCodeCompletionConsumer();
|
||||
|
||||
// Run the AST consumer action.
|
||||
CodeCompleteConsumer *CompletionConsumer =
|
||||
CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer() : 0;
|
||||
ParseAST(PP, Consumer.get(), CI.getASTContext(), FEOpts.ShowStats,
|
||||
CompleteTranslationUnit, CompletionConsumer);
|
||||
} else {
|
||||
// Run the preprocessor actions.
|
||||
llvm::TimeRegion Timer(ClangFrontendTimer);
|
||||
switch (PA) {
|
||||
default:
|
||||
assert(0 && "unexpected program action");
|
||||
|
||||
case DumpRawTokens: {
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
// Start lexing the specified input file.
|
||||
Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
|
||||
RawLex.SetKeepWhitespaceMode(true);
|
||||
|
||||
Token RawTok;
|
||||
RawLex.LexFromRawLexer(RawTok);
|
||||
while (RawTok.isNot(tok::eof)) {
|
||||
PP.DumpToken(RawTok, true);
|
||||
fprintf(stderr, "\n");
|
||||
RawLex.LexFromRawLexer(RawTok);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DumpTokens: {
|
||||
Token Tok;
|
||||
// Start preprocessing the specified input file.
|
||||
PP.EnterMainSourceFile();
|
||||
do {
|
||||
PP.Lex(Tok);
|
||||
PP.DumpToken(Tok, true);
|
||||
fprintf(stderr, "\n");
|
||||
} while (Tok.isNot(tok::eof));
|
||||
break;
|
||||
}
|
||||
|
||||
case GeneratePTH:
|
||||
if (FEOpts.OutputFile.empty() || FEOpts.OutputFile == "-") {
|
||||
// FIXME: Don't fail this way.
|
||||
// FIXME: Verify that we can actually seek in the given file.
|
||||
llvm::errs() << "ERROR: PTH requires an seekable file for output!\n";
|
||||
::exit(1);
|
||||
}
|
||||
CacheTokens(PP, CI.createDefaultOutputFile(true, InFile));
|
||||
break;
|
||||
|
||||
case ParseNoop:
|
||||
ParseFile(PP, new MinimalAction(PP));
|
||||
break;
|
||||
|
||||
case ParsePrintCallbacks: {
|
||||
llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile);
|
||||
ParseFile(PP, CreatePrintParserActionsAction(PP, OS));
|
||||
break;
|
||||
}
|
||||
case PrintPreprocessedInput:
|
||||
DoPrintPreprocessedInput(PP, CI.createDefaultOutputFile(false, InFile),
|
||||
CI.getPreprocessorOutputOpts());
|
||||
break;
|
||||
|
||||
case RewriteMacros:
|
||||
RewriteMacrosInInput(PP, CI.createDefaultOutputFile(true, InFile));
|
||||
break;
|
||||
|
||||
case RewriteTest:
|
||||
DoRewriteTest(PP, CI.createDefaultOutputFile(false, InFile));
|
||||
break;
|
||||
|
||||
case RunPreprocessorOnly: { // Just lex as fast as we can, no output.
|
||||
Token Tok;
|
||||
// Start parsing the specified input file.
|
||||
PP.EnterMainSourceFile();
|
||||
do {
|
||||
PP.Lex(Tok);
|
||||
} while (Tok.isNot(tok::eof));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FixItRewrite)
|
||||
FixItRewrite->WriteFixedFile(InFile, FEOpts.OutputFile);
|
||||
|
||||
// Release the consumer and the AST, in that order since the consumer may
|
||||
// perform actions in its destructor which require the context.
|
||||
if (FEOpts.DisableFree) {
|
||||
Consumer.take();
|
||||
CI.takeASTContext();
|
||||
} else {
|
||||
Consumer.reset();
|
||||
CI.setASTContext(0);
|
||||
}
|
||||
|
||||
if (FEOpts.ShowStats) {
|
||||
fprintf(stderr, "\nSTATISTICS FOR '%s':\n", InFile.c_str());
|
||||
PP.PrintStats();
|
||||
PP.getIdentifierTable().PrintStats();
|
||||
PP.getHeaderSearchInfo().PrintStats();
|
||||
PP.getSourceManager().PrintStats();
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
// Cleanup the output streams, and erase the output files if we encountered an
|
||||
// error.
|
||||
CI.ClearOutputFiles(/*EraseFiles=*/PP.getDiagnostics().getNumErrors());
|
||||
}
|
||||
|
||||
/// ProcessASTInputFile - Process a single AST input file with the specified
|
||||
/// state.
|
||||
static void ProcessASTInputFile(CompilerInstance &CI, const std::string &InFile,
|
||||
ProgActions PA) {
|
||||
std::string Error;
|
||||
llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, &Error));
|
||||
if (!AST) {
|
||||
CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error;
|
||||
return;
|
||||
}
|
||||
|
||||
Preprocessor &PP = AST->getPreprocessor();
|
||||
llvm::OwningPtr<ASTConsumer> Consumer(CreateConsumerAction(CI, PP,
|
||||
InFile, PA));
|
||||
if (!Consumer.get()) {
|
||||
CI.getDiagnostics().Report(diag::err_fe_invalid_ast_action);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the main file ID to an empty file.
|
||||
//
|
||||
// FIXME: We probably shouldn't need this, but for now this is the simplest
|
||||
// way to reuse the logic in ParseAST.
|
||||
const char *EmptyStr = "";
|
||||
llvm::MemoryBuffer *SB =
|
||||
llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>");
|
||||
AST->getSourceManager().createMainFileIDForMemBuffer(SB);
|
||||
|
||||
// Stream the input AST to the consumer.
|
||||
CI.getDiagnostics().getClient()->BeginSourceFile(PP.getLangOptions(), &PP);
|
||||
ParseAST(PP, Consumer.get(), AST->getASTContext(),
|
||||
CI.getFrontendOpts().ShowStats);
|
||||
CI.getDiagnostics().getClient()->EndSourceFile();
|
||||
|
||||
// Release the consumer and the AST, in that order since the consumer may
|
||||
// perform actions in its destructor which require the context.
|
||||
if (CI.getFrontendOpts().DisableFree) {
|
||||
Consumer.take();
|
||||
AST.take();
|
||||
} else {
|
||||
Consumer.reset();
|
||||
AST.reset();
|
||||
}
|
||||
|
||||
// Cleanup the output streams, and erase the output files if we encountered an
|
||||
// error.
|
||||
CI.ClearOutputFiles(/*EraseFiles=*/PP.getDiagnostics().getNumErrors());
|
||||
}
|
||||
|
||||
static void LLVMErrorHandler(void *UserData, const std::string &Message) {
|
||||
@@ -701,33 +348,35 @@ int main(int argc, char **argv) {
|
||||
if (!Clang.getFrontendOpts().FixItLocations.empty())
|
||||
ProgAction = FixIt;
|
||||
|
||||
// Create the source manager.
|
||||
Clang.createSourceManager();
|
||||
|
||||
// Create a file manager object to provide access to and cache the filesystem.
|
||||
Clang.createFileManager();
|
||||
|
||||
for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) {
|
||||
const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second;
|
||||
|
||||
// AST inputs are handled specially.
|
||||
if (IsAST) {
|
||||
ProcessASTInputFile(Clang, InFile, ProgAction);
|
||||
continue;
|
||||
// If we aren't using an AST file, setup the file and source managers and
|
||||
// the preprocessor.
|
||||
if (!IsAST) {
|
||||
if (!i) {
|
||||
// Create a file manager object to provide access to and cache the
|
||||
// filesystem.
|
||||
Clang.createFileManager();
|
||||
|
||||
// Create the source manager.
|
||||
Clang.createSourceManager();
|
||||
} else {
|
||||
// Reset the ID tables if we are reusing the SourceManager.
|
||||
Clang.getSourceManager().clearIDTables();
|
||||
}
|
||||
|
||||
// Create the preprocessor.
|
||||
Clang.createPreprocessor();
|
||||
}
|
||||
|
||||
// Reset the ID tables if we are reusing the SourceManager.
|
||||
if (i)
|
||||
Clang.getSourceManager().clearIDTables();
|
||||
|
||||
// Create the preprocessor.
|
||||
Clang.createPreprocessor();
|
||||
|
||||
// Process the source file.
|
||||
Clang.getDiagnostics().getClient()->BeginSourceFile(Clang.getLangOpts(),
|
||||
&Clang.getPreprocessor());
|
||||
ProcessInputFile(Clang, InFile, ProgAction);
|
||||
Clang.getDiagnostics().getClient()->EndSourceFile();
|
||||
llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(ProgAction));
|
||||
assert(Act && "Invalid program action!");
|
||||
Act->setCurrentTimer(ClangFrontendTimer);
|
||||
if (Act->BeginSourceFile(Clang, InFile, IsAST)) {
|
||||
Act->Execute();
|
||||
Act->EndSourceFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (Clang.getDiagnosticOpts().ShowCarets)
|
||||
|
||||
Reference in New Issue
Block a user