// original C code. The output is intended to be in a format such that
// clang could re-parse the output back into the same AST, but the
// implementation is still incomplete.
-ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS = NULL);
+ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS);
// AST dumper: dumps the raw AST in human-readable form to stderr; this is
// intended for debugging. A normal dump is done with FullDump = false;
// ObjC rewriter: attempts tp rewrite ObjC constructs into pure C code.
// This is considered experimental, and only works with Apple's ObjC runtime.
ASTConsumer *CreateCodeRewriterTest(const std::string& InFile,
- const std::string& OutFile,
+ llvm::raw_ostream* OS,
Diagnostic &Diags,
const LangOptions &LOpts);
Diagnostic &Diags,
const LangOptions &Features,
const CompileOptions &CompileOpts,
- const std::string &InFile,
- const std::string &OutFile);
+ const std::string &ModuleID,
+ llvm::raw_ostream *OS);
// HTML printer: uses the rewriter to convert source code to HTML with
// syntax highlighting suitable for viewing in a web-browser.
-ASTConsumer* CreateHTMLPrinter(const std::string &OutFile, Diagnostic &D,
+ASTConsumer* CreateHTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D,
Preprocessor *PP, PreprocessorFactory *PPF);
// PCH generator: generates a precompiled header file; this file can be
// used later with the PCHReader (clang-cc option -include-pch)
// to speed up compile times.
ASTConsumer *CreatePCHGenerator(const Preprocessor &PP,
- const std::string &OutFile);
+ llvm::raw_ostream *OS);
// Block rewriter: rewrites code using the Apple blocks extension to pure
-// C code.
+// C code. Output is always sent to stdout.
ASTConsumer *CreateBlockRewriter(const std::string &InFile,
- const std::string &OutFile,
Diagnostic &Diags,
const LangOptions &LangOpts);
class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
BackendAction Action;
CompileOptions CompileOpts;
- const std::string &InputFile;
- std::string OutputFile;
+ llvm::raw_ostream *AsmOutStream;
ASTContext *Context;
Timer LLVMIRGeneration;
llvm::Module *TheModule;
llvm::TargetData *TheTargetData;
- llvm::raw_ostream *AsmOutStream;
mutable llvm::ModuleProvider *ModuleProvider;
mutable FunctionPassManager *CodeGenPasses;
public:
BackendConsumer(BackendAction action, Diagnostic &Diags,
const LangOptions &langopts, const CompileOptions &compopts,
- const std::string &infile, const std::string &outfile) :
+ const std::string &infile, llvm::raw_ostream* OS) :
Action(action),
CompileOpts(compopts),
- InputFile(infile),
- OutputFile(outfile),
+ AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
CodeGenerationTime("Code Generation Time"),
- Gen(CreateLLVMCodeGen(Diags, InputFile, compopts)),
- TheModule(0), TheTargetData(0), AsmOutStream(0), ModuleProvider(0),
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts)),
+ TheModule(0), TheTargetData(0), ModuleProvider(0),
CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {
// Enable -time-passes if -ftime-report is enabled.
}
~BackendConsumer() {
- delete AsmOutStream;
delete TheTargetData;
delete ModuleProvider;
delete CodeGenPasses;
if (Action == Backend_EmitNothing)
return true;
- if (OutputFile == "-" || (InputFile == "-" && OutputFile.empty())) {
- AsmOutStream = new raw_stdout_ostream();
- sys::Program::ChangeStdoutToBinary();
- } else {
- if (OutputFile.empty()) {
- llvm::sys::Path Path(InputFile);
- Path.eraseSuffix();
- if (Action == Backend_EmitBC) {
- Path.appendSuffix("bc");
- } else if (Action == Backend_EmitLL) {
- Path.appendSuffix("ll");
- } else {
- Path.appendSuffix("s");
- }
- OutputFile = Path.toString();
- }
-
- AsmOutStream = new raw_fd_ostream(OutputFile.c_str(), true, Error);
- if (!Error.empty())
- return false;
- }
-
if (Action == Backend_EmitBC) {
getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream));
} else if (Action == Backend_EmitLL) {
const LangOptions &LangOpts,
const CompileOptions &CompileOpts,
const std::string& InFile,
- const std::string& OutFile) {
- return new BackendConsumer(Action, Diags, LangOpts, CompileOpts,
- InFile, OutFile);
+ llvm::raw_ostream* OS) {
+ return new BackendConsumer(Action, Diags, LangOpts, CompileOpts, InFile, OS);
}
namespace {
class VISIBILITY_HIDDEN PCHGenerator : public SemaConsumer {
const Preprocessor &PP;
- std::string OutFile;
+ llvm::raw_ostream *Out;
Sema *SemaPtr;
MemorizeStatCalls *StatCalls; // owned by the FileManager
public:
- explicit PCHGenerator(const Preprocessor &PP, const std::string &OutFile);
+ explicit PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *Out);
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
};
}
-PCHGenerator::PCHGenerator(const Preprocessor &PP, const std::string &OutFile)
- : PP(PP), OutFile(OutFile), SemaPtr(0), StatCalls(0) {
+PCHGenerator::PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS)
+ : PP(PP), Out(OS), SemaPtr(0), StatCalls(0) {
// Install a stat() listener to keep track of all of the stat()
// calls.
assert(SemaPtr && "No Sema?");
Writer.WritePCH(*SemaPtr, StatCalls);
- // Open up the PCH file.
- std::string ErrMsg;
- llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg);
-
- if (!ErrMsg.empty()) {
- llvm::errs() << "PCH error: " << ErrMsg << "\n";
- return;
- }
-
// Write the generated bitstream to "Out".
- Out.write((char *)&Buffer.front(), Buffer.size());
+ Out->write((char *)&Buffer.front(), Buffer.size());
// Make sure it hits disk now.
- Out.flush();
+ Out->flush();
}
ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP,
- const std::string &OutFile) {
- return new PCHGenerator(PP, OutFile);
+ llvm::raw_ostream *OS) {
+ return new PCHGenerator(PP, OS);
}
namespace {
class HTMLPrinter : public ASTConsumer {
Rewriter R;
- std::string OutFilename;
+ llvm::raw_ostream *Out;
Diagnostic &Diags;
Preprocessor *PP;
PreprocessorFactory *PPF;
public:
- HTMLPrinter(const std::string &OutFile, Diagnostic &D, Preprocessor *pp,
+ HTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D, Preprocessor *pp,
PreprocessorFactory* ppf)
- : OutFilename(OutFile), Diags(D), PP(pp), PPF(ppf) {}
+ : Out(OS), Diags(D), PP(pp), PPF(ppf) {}
virtual ~HTMLPrinter();
void Initialize(ASTContext &context);
};
}
-ASTConsumer* clang::CreateHTMLPrinter(const std::string &OutFile,
+ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS,
Diagnostic &D, Preprocessor *PP,
PreprocessorFactory* PPF) {
- return new HTMLPrinter(OutFile, D, PP, PPF);
+ return new HTMLPrinter(OS, D, PP, PPF);
}
void HTMLPrinter::Initialize(ASTContext &context) {
if (PP) html::SyntaxHighlight(R, FID, *PP);
if (PPF) html::HighlightMacros(R, FID, *PP);
html::EscapeText(R, FID, false, true);
-
- // Open the output.
- FILE *OutputFILE;
- if (OutFilename.empty() || OutFilename == "-")
- OutputFILE = stdout;
- else {
- OutputFILE = fopen(OutFilename.c_str(), "w+");
- if (OutputFILE == 0) {
- fprintf(stderr, "Error opening output file '%s'.\n", OutFilename.c_str());
- exit(1);
- }
- }
-
+
// Emit the HTML.
const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID);
char *Buffer = (char*)malloc(RewriteBuf.size());
std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer);
- fwrite(Buffer, 1, RewriteBuf.size(), OutputFILE);
+ Out->write(Buffer, RewriteBuf.size());
free(Buffer);
-
- if (OutputFILE != stdout) fclose(OutputFILE);
}
ObjCMethodDecl *CurMethodDef;
bool IsHeader;
- std::string InFileName;
- std::string OutFileName;
std::string Preamble;
public:
- RewriteBlocks(std::string inFile, std::string outFile, Diagnostic &D,
+ RewriteBlocks(std::string inFile, Diagnostic &D,
const LangOptions &LOpts);
~RewriteBlocks() {
// Get the buffer corresponding to MainFileID.
return Ext == "h" || Ext == "hh" || Ext == "H";
}
-RewriteBlocks::RewriteBlocks(std::string inFile, std::string outFile,
+RewriteBlocks::RewriteBlocks(std::string inFile,
Diagnostic &D, const LangOptions &LOpts) :
Diags(D), LangOpts(LOpts) {
IsHeader = IsHeaderFile(inFile);
- InFileName = inFile;
- OutFileName = outFile;
CurFunctionDef = 0;
CurMethodDef = 0;
RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
}
ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
- const std::string& OutFile,
Diagnostic &Diags,
const LangOptions &LangOpts) {
- return new RewriteBlocks(InFile, OutFile, Diags, LangOpts);
+ return new RewriteBlocks(InFile, Diags, LangOpts);
}
void RewriteBlocks::Initialize(ASTContext &context) {
bool IsHeader;
std::string InFileName;
- std::string OutFileName;
+ llvm::raw_ostream* OutFile;
std::string Preamble;
}
void HandleTopLevelSingleDecl(Decl *D);
void HandleDeclInMainFile(Decl *D);
- RewriteObjC(std::string inFile, std::string outFile,
+ RewriteObjC(std::string inFile, llvm::raw_ostream *OS,
Diagnostic &D, const LangOptions &LOpts);
~RewriteObjC() {}
return Ext == "h" || Ext == "hh" || Ext == "H";
}
-RewriteObjC::RewriteObjC(std::string inFile, std::string outFile,
+RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS,
Diagnostic &D, const LangOptions &LOpts)
- : Diags(D), LangOpts(LOpts) {
+ : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS) {
IsHeader = IsHeaderFile(inFile);
- InFileName = inFile;
- OutFileName = outFile;
RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
"rewriting sub-expression within a macro (may not be correct)");
TryFinallyContainsReturnDiag = Diags.getCustomDiagID(Diagnostic::Warning,
}
ASTConsumer *clang::CreateCodeRewriterTest(const std::string& InFile,
- const std::string& OutFile,
+ llvm::raw_ostream* OS,
Diagnostic &Diags,
const LangOptions &LOpts) {
- return new RewriteObjC(InFile, OutFile, Diags, LOpts);
+ return new RewriteObjC(InFile, OS, Diags, LOpts);
}
void RewriteObjC::Initialize(ASTContext &context) {
if (Diags.hasErrorOccurred())
return;
-
- // Create the output file.
-
- llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
- llvm::raw_ostream *OutFile;
- if (OutFileName == "-") {
- OutFile = &llvm::outs();
- } else if (!OutFileName.empty()) {
- std::string Err;
- OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(),
- // set binary mode (critical for Windoze)
- true,
- Err);
- OwnedStream.reset(OutFile);
- } else if (InFileName == "-") {
- OutFile = &llvm::outs();
- } else {
- llvm::sys::Path Path(InFileName);
- Path.eraseSuffix();
- Path.appendSuffix("cpp");
- std::string Err;
- OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(),
- // set binary mode (critical for Windoze)
- true,
- Err);
- OwnedStream.reset(OutFile);
- }
RewriteInclude();
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Streams.h"
#include "llvm/Support/Timer.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/System/Process.h"
+#include "llvm/System/Program.h"
#include "llvm/System/Signals.h"
#include <cstdlib>
#if HAVE_SYS_TYPES_H
// Main driver
//===----------------------------------------------------------------------===//
-/// CreateASTConsumer - Create the ASTConsumer for the corresponding program
-/// action. These consumers can operate on both ASTs that are freshly
-/// parsed from source files as well as those deserialized from Bitcode.
-/// Note that PP and PPF may be null here.
-static ASTConsumer *CreateASTConsumer(const std::string& InFile,
- Diagnostic& Diag, FileManager& FileMgr,
- const LangOptions& LangOpts,
- const llvm::StringMap<bool>& Features,
- Preprocessor *PP,
- PreprocessorFactory *PPF) {
- switch (ProgAction) {
+static llvm::raw_ostream* ComputeOutFile(const std::string& InFile,
+ const char* Extension,
+ bool Binary,
+ llvm::sys::Path& OutPath) {
+ llvm::raw_ostream* Ret;
+ bool UseStdout = false;
+ std::string OutFile;
+ if (OutputFile == "-" || (OutputFile.empty() && InFile == "-")) {
+ UseStdout = true;
+ } else if (!OutputFile.empty()) {
+ OutFile = OutputFile;
+ } else if (Extension) {
+ llvm::sys::Path Path(InFile);
+ Path.eraseSuffix();
+ Path.appendSuffix(Extension);
+ OutFile = Path.toString();
+ } else {
+ UseStdout = true;
+ }
+
+ if (UseStdout) {
+ Ret = new llvm::raw_stdout_ostream();
+ if (Binary)
+ llvm::sys::Program::ChangeStdoutToBinary();
+ } else {
+ std::string Error;
+ Ret = new llvm::raw_fd_ostream(OutFile.c_str(), Binary, Error);
+ if (!Error.empty()) {
+ // FIXME: Don't fail this way.
+ llvm::cerr << "ERROR: " << Error << "\n";
+ ::exit(1);
+ }
+ OutPath = OutFile;
+ }
+
+ return Ret;
+}
+
+/// ProcessInputFile - Process a single input file with the specified state.
+///
+static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
+ const std::string &InFile, ProgActions PA,
+ const llvm::StringMap<bool> &Features) {
+ llvm::OwningPtr<llvm::raw_ostream> OS;
+ llvm::OwningPtr<ASTConsumer> Consumer;
+ bool ClearSourceMgr = false;
+ FixItRewriter *FixItRewrite = 0;
+ bool CompleteTranslationUnit = true;
+ llvm::sys::Path OutPath;
+
+ switch (PA) {
default:
- return NULL;
-
+ fprintf(stderr, "Unexpected program action!\n");
+ HadErrors = true;
+ return;
+
case ASTPrint:
- return CreateASTPrinter();
+ OS.reset(ComputeOutFile(InFile, 0, false, OutPath));
+ Consumer.reset(CreateASTPrinter(OS.get()));
+ break;
case ASTDump:
- return CreateASTDumper(false);
+ Consumer.reset(CreateASTDumper(false));
+ break;
case ASTDumpFull:
- return CreateASTDumper(true);
+ Consumer.reset(CreateASTDumper(true));
+ break;
case ASTView:
- return CreateASTViewer();
+ Consumer.reset(CreateASTViewer());
+ break;
case PrintDeclContext:
- return CreateDeclContextPrinter();
-
+ Consumer.reset(CreateDeclContextPrinter());
+ break;
+
case EmitHTML:
- return CreateHTMLPrinter(OutputFile, Diag, PP, PPF);
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ Consumer.reset(CreateHTMLPrinter(OS.get(), PP.getDiagnostics(), &PP, &PPF));
+ break;
case InheritanceView:
- return CreateInheritanceViewer(InheritanceViewCls);
-
+ Consumer.reset(CreateInheritanceViewer(InheritanceViewCls));
+ break;
+
case EmitAssembly:
case EmitLLVM:
case EmitBC:
case EmitLLVMOnly: {
BackendAction Act;
- if (ProgAction == EmitAssembly)
+ if (ProgAction == EmitAssembly) {
Act = Backend_EmitAssembly;
- else if (ProgAction == EmitLLVM)
+ OS.reset(ComputeOutFile(InFile, "s", true, OutPath));
+ } else if (ProgAction == EmitLLVM) {
Act = Backend_EmitLL;
- else if (ProgAction == EmitLLVMOnly)
+ OS.reset(ComputeOutFile(InFile, "ll", true, OutPath));
+ } else if (ProgAction == EmitLLVMOnly) {
Act = Backend_EmitNothing;
- else
+ } else {
Act = Backend_EmitBC;
-
+ OS.reset(ComputeOutFile(InFile, "bc", true, OutPath));
+ }
+
CompileOptions Opts;
- InitializeCompileOptions(Opts, LangOpts, Features);
- return CreateBackendConsumer(Act, Diag, LangOpts, Opts,
- InFile, OutputFile);
+ InitializeCompileOptions(Opts, PP.getLangOptions(), Features);
+ Consumer.reset(CreateBackendConsumer(Act, PP.getDiagnostics(),
+ PP.getLangOptions(), Opts, InFile,
+ OS.get()));
+ break;
}
case GeneratePCH:
- return CreatePCHGenerator(*PP, OutputFile);
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ Consumer.reset(CreatePCHGenerator(PP, OS.get()));
+ CompleteTranslationUnit = false;
+ break;
case RewriteObjC:
- return CreateCodeRewriterTest(InFile, OutputFile, Diag, LangOpts);
+ OS.reset(ComputeOutFile(InFile, "cpp", true, OutPath));
+ Consumer.reset(CreateCodeRewriterTest(InFile, OS.get(),
+ PP.getDiagnostics(),
+ PP.getLangOptions()));
+ break;
case RewriteBlocks:
- return CreateBlockRewriter(InFile, OutputFile, Diag, LangOpts);
-
- case RunAnalysis:
- return CreateAnalysisConsumer(Diag, PP, PPF, LangOpts, OutputFile);
- }
-}
-
-/// ProcessInputFile - Process a single input file with the specified state.
-///
-static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
- const std::string &InFile, ProgActions PA,
- const llvm::StringMap<bool> &Features) {
- llvm::OwningPtr<ASTConsumer> Consumer;
- bool ClearSourceMgr = false;
- FixItRewriter *FixItRewrite = 0;
- bool CompleteTranslationUnit = true;
-
- switch (PA) {
- default:
- Consumer.reset(CreateASTConsumer(InFile, PP.getDiagnostics(),
- PP.getFileManager(), PP.getLangOptions(),
- Features, &PP, &PPF));
-
- if (!Consumer) {
- fprintf(stderr, "Unexpected program action!\n");
- HadErrors = true;
- return;
- }
+ Consumer.reset(CreateBlockRewriter(InFile, PP.getDiagnostics(),
+ PP.getLangOptions()));
+ break;
- if (ProgAction == GeneratePCH)
- CompleteTranslationUnit = false;
+ case RunAnalysis:
+ Consumer.reset(CreateAnalysisConsumer(PP.getDiagnostics(), &PP, &PPF,
+ PP.getLangOptions(), OutputFile));
break;
-
+
case DumpRawTokens: {
llvm::TimeRegion Timer(ClangFrontendTimer);
SourceManager &SM = PP.getSourceManager();
ContextOwner.take();
else
ContextOwner.reset(); // Delete ASTContext
-
+
if (VerifyDiagnostics)
if (CheckDiagnostics(PP))
exit(1);
if (DisableFree)
Consumer.take();
+ else
+ Consumer.reset();
+
+ // Always delete the output stream because we don't want to leak file
+ // handles. Also, we don't want to try to erase an open file.
+ OS.reset();
+
+ if ((HadErrors || (PP.getDiagnostics().getNumErrors() != 0)) &&
+ !OutPath.isEmpty()) {
+ // If we had errors, try to erase the output file.
+ OutPath.eraseFromDisk();
+ }
}
static llvm::cl::list<std::string>