mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-07 15:46:05 +00:00

too low-level to actually be useful but is just interesting enough for people to try to use it (which won't actually work beyond toy examples). To bring back the AST printer, it needs to be: - Complete, covering all of C/C++/Objective-C - Documented, with appropriate Schema against which we can validate the output - Designed for C/C++/Objective-C, not Clang's specific ASTs - Stable across Clang versions - Well-tested llvm-svn: 127141
225 lines
7.5 KiB
C++
225 lines
7.5 KiB
C++
//===--- FrontendActions.cpp ----------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Frontend/FrontendActions.h"
|
|
#include "clang/AST/ASTConsumer.h"
|
|
#include "clang/Lex/Pragma.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
#include "clang/Parse/Parser.h"
|
|
#include "clang/Basic/FileManager.h"
|
|
#include "clang/Frontend/ASTConsumers.h"
|
|
#include "clang/Frontend/ASTUnit.h"
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
|
#include "clang/Frontend/Utils.h"
|
|
#include "clang/Serialization/ASTWriter.h"
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace clang;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Custom Actions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
return new ASTConsumer();
|
|
}
|
|
|
|
void InitOnlyAction::ExecuteAction() {
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// AST Consumer Actions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
|
|
return CreateASTPrinter(OS);
|
|
return 0;
|
|
}
|
|
|
|
ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
return CreateASTDumper();
|
|
}
|
|
|
|
ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
llvm::raw_ostream *OS;
|
|
if (CI.getFrontendOpts().OutputFile.empty())
|
|
OS = &llvm::outs();
|
|
else
|
|
OS = CI.createDefaultOutputFile(false, InFile);
|
|
if (!OS) return 0;
|
|
return CreateASTDumperXML(*OS);
|
|
}
|
|
|
|
ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
return CreateASTViewer();
|
|
}
|
|
|
|
ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
return CreateDeclContextPrinter();
|
|
}
|
|
|
|
ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
std::string Sysroot;
|
|
std::string OutputFile;
|
|
llvm::raw_ostream *OS = 0;
|
|
bool Chaining;
|
|
if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining))
|
|
return 0;
|
|
|
|
const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
|
|
Sysroot.c_str() : 0;
|
|
return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, isysroot, OS);
|
|
}
|
|
|
|
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
|
|
llvm::StringRef InFile,
|
|
std::string &Sysroot,
|
|
std::string &OutputFile,
|
|
llvm::raw_ostream *&OS,
|
|
bool &Chaining) {
|
|
Sysroot = CI.getHeaderSearchOpts().Sysroot;
|
|
if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) {
|
|
CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot);
|
|
return true;
|
|
}
|
|
|
|
// We use createOutputFile here because this is exposed via libclang, and we
|
|
// must disable the RemoveFileOnSignal behavior.
|
|
OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true,
|
|
/*RemoveFileOnSignal=*/false, InFile);
|
|
if (!OS)
|
|
return true;
|
|
|
|
OutputFile = CI.getFrontendOpts().OutputFile;
|
|
Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH &&
|
|
!CI.getPreprocessorOpts().ImplicitPCHInclude.empty();
|
|
return false;
|
|
}
|
|
|
|
ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
|
|
llvm::StringRef InFile) {
|
|
return new ASTConsumer();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Preprocessor Actions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void DumpRawTokensAction::ExecuteAction() {
|
|
Preprocessor &PP = getCompilerInstance().getPreprocessor();
|
|
SourceManager &SM = PP.getSourceManager();
|
|
|
|
// Start lexing the specified input file.
|
|
const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
|
|
Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
|
|
RawLex.SetKeepWhitespaceMode(true);
|
|
|
|
Token RawTok;
|
|
RawLex.LexFromRawLexer(RawTok);
|
|
while (RawTok.isNot(tok::eof)) {
|
|
PP.DumpToken(RawTok, true);
|
|
llvm::errs() << "\n";
|
|
RawLex.LexFromRawLexer(RawTok);
|
|
}
|
|
}
|
|
|
|
void DumpTokensAction::ExecuteAction() {
|
|
Preprocessor &PP = getCompilerInstance().getPreprocessor();
|
|
// Start preprocessing the specified input file.
|
|
Token Tok;
|
|
PP.EnterMainSourceFile();
|
|
do {
|
|
PP.Lex(Tok);
|
|
PP.DumpToken(Tok, true);
|
|
llvm::errs() << "\n";
|
|
} while (Tok.isNot(tok::eof));
|
|
}
|
|
|
|
void GeneratePTHAction::ExecuteAction() {
|
|
CompilerInstance &CI = getCompilerInstance();
|
|
if (CI.getFrontendOpts().OutputFile.empty() ||
|
|
CI.getFrontendOpts().OutputFile == "-") {
|
|
// FIXME: Don't fail this way.
|
|
// FIXME: Verify that we can actually seek in the given file.
|
|
llvm::report_fatal_error("PTH requires a seekable file for output!");
|
|
}
|
|
llvm::raw_fd_ostream *OS =
|
|
CI.createDefaultOutputFile(true, getCurrentFile());
|
|
if (!OS) return;
|
|
|
|
CacheTokens(CI.getPreprocessor(), OS);
|
|
}
|
|
|
|
void PreprocessOnlyAction::ExecuteAction() {
|
|
Preprocessor &PP = getCompilerInstance().getPreprocessor();
|
|
|
|
// Ignore unknown pragmas.
|
|
PP.AddPragmaHandler(new EmptyPragmaHandler());
|
|
|
|
Token Tok;
|
|
// Start parsing the specified input file.
|
|
PP.EnterMainSourceFile();
|
|
do {
|
|
PP.Lex(Tok);
|
|
} while (Tok.isNot(tok::eof));
|
|
}
|
|
|
|
void PrintPreprocessedAction::ExecuteAction() {
|
|
CompilerInstance &CI = getCompilerInstance();
|
|
// Output file needs to be set to 'Binary', to avoid converting Unix style
|
|
// line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
|
|
llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
|
|
if (!OS) return;
|
|
|
|
DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
|
|
CI.getPreprocessorOutputOpts());
|
|
}
|
|
|
|
void PrintPreambleAction::ExecuteAction() {
|
|
switch (getCurrentFileKind()) {
|
|
case IK_C:
|
|
case IK_CXX:
|
|
case IK_ObjC:
|
|
case IK_ObjCXX:
|
|
case IK_OpenCL:
|
|
case IK_CUDA:
|
|
break;
|
|
|
|
case IK_None:
|
|
case IK_Asm:
|
|
case IK_PreprocessedC:
|
|
case IK_PreprocessedCXX:
|
|
case IK_PreprocessedObjC:
|
|
case IK_PreprocessedObjCXX:
|
|
case IK_AST:
|
|
case IK_LLVM_IR:
|
|
// We can't do anything with these.
|
|
return;
|
|
}
|
|
|
|
CompilerInstance &CI = getCompilerInstance();
|
|
llvm::MemoryBuffer *Buffer
|
|
= CI.getFileManager().getBufferForFile(getCurrentFile());
|
|
if (Buffer) {
|
|
unsigned Preamble = Lexer::ComputePreamble(Buffer).first;
|
|
llvm::outs().write(Buffer->getBufferStart(), Preamble);
|
|
delete Buffer;
|
|
}
|
|
}
|