Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@ -0,0 +1,23 @@
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_library(clangRewriteFrontend
FixItRewriter.cpp
FrontendActions.cpp
HTMLPrint.cpp
InclusionRewriter.cpp
RewriteMacros.cpp
RewriteModernObjC.cpp
RewriteObjC.cpp
RewriteTest.cpp
LINK_LIBS
clangAST
clangBasic
clangEdit
clangFrontend
clangLex
clangRewrite
clangSerialization
)

View File

@ -0,0 +1,203 @@
//===--- FixItRewriter.cpp - Fix-It Rewriter Diagnostic Client --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is a diagnostic client adaptor that performs rewrites as
// suggested by code modification hints attached to diagnostics. It
// then forwards any diagnostics to the adapted diagnostic client.
//
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <memory>
using namespace clang;
FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
const LangOptions &LangOpts,
FixItOptions *FixItOpts)
: Diags(Diags),
Editor(SourceMgr, LangOpts),
Rewrite(SourceMgr, LangOpts),
FixItOpts(FixItOpts),
NumFailures(0),
PrevDiagSilenced(false) {
Owner = Diags.takeClient();
Client = Diags.getClient();
Diags.setClient(this, false);
}
FixItRewriter::~FixItRewriter() {
Diags.setClient(Client, Owner.release() != nullptr);
}
bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID);
if (!RewriteBuf) return true;
RewriteBuf->write(OS);
OS.flush();
return false;
}
namespace {
class RewritesReceiver : public edit::EditsReceiver {
Rewriter &Rewrite;
public:
RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
void insert(SourceLocation loc, StringRef text) override {
Rewrite.InsertText(loc, text);
}
void replace(CharSourceRange range, StringRef text) override {
Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
}
};
}
bool FixItRewriter::WriteFixedFiles(
std::vector<std::pair<std::string, std::string> > *RewrittenFiles) {
if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) {
Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
return true;
}
RewritesReceiver Rec(Rewrite);
Editor.applyRewrites(Rec);
if (FixItOpts->InPlace) {
// Overwriting open files on Windows is tricky, but the rewriter can do it
// for us.
Rewrite.overwriteChangedFiles();
return false;
}
for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
int fd;
std::string Filename = FixItOpts->RewriteFilename(Entry->getName(), fd);
std::error_code EC;
std::unique_ptr<llvm::raw_fd_ostream> OS;
if (fd != -1) {
OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
} else {
OS.reset(new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
}
if (EC) {
Diags.Report(clang::diag::err_fe_unable_to_open_output) << Filename
<< EC.message();
continue;
}
RewriteBuffer &RewriteBuf = I->second;
RewriteBuf.write(*OS);
OS->flush();
if (RewrittenFiles)
RewrittenFiles->push_back(std::make_pair(Entry->getName(), Filename));
}
return false;
}
bool FixItRewriter::IncludeInDiagnosticCounts() const {
return Client ? Client->IncludeInDiagnosticCounts() : true;
}
void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
// Default implementation (Warnings/errors count).
DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
if (!FixItOpts->Silent ||
DiagLevel >= DiagnosticsEngine::Error ||
(DiagLevel == DiagnosticsEngine::Note && !PrevDiagSilenced) ||
(DiagLevel > DiagnosticsEngine::Note && Info.getNumFixItHints())) {
Client->HandleDiagnostic(DiagLevel, Info);
PrevDiagSilenced = false;
} else {
PrevDiagSilenced = true;
}
// Skip over any diagnostics that are ignored or notes.
if (DiagLevel <= DiagnosticsEngine::Note)
return;
// Skip over errors if we are only fixing warnings.
if (DiagLevel >= DiagnosticsEngine::Error && FixItOpts->FixOnlyWarnings) {
++NumFailures;
return;
}
// Make sure that we can perform all of the modifications we
// in this diagnostic.
edit::Commit commit(Editor);
for (unsigned Idx = 0, Last = Info.getNumFixItHints();
Idx < Last; ++Idx) {
const FixItHint &Hint = Info.getFixItHint(Idx);
if (Hint.CodeToInsert.empty()) {
if (Hint.InsertFromRange.isValid())
commit.insertFromRange(Hint.RemoveRange.getBegin(),
Hint.InsertFromRange, /*afterToken=*/false,
Hint.BeforePreviousInsertions);
else
commit.remove(Hint.RemoveRange);
} else {
if (Hint.RemoveRange.isTokenRange() ||
Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
commit.replace(Hint.RemoveRange, Hint.CodeToInsert);
else
commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
/*afterToken=*/false, Hint.BeforePreviousInsertions);
}
}
bool CanRewrite = Info.getNumFixItHints() > 0 && commit.isCommitable();
if (!CanRewrite) {
if (Info.getNumFixItHints() > 0)
Diag(Info.getLocation(), diag::note_fixit_in_macro);
// If this was an error, refuse to perform any rewriting.
if (DiagLevel >= DiagnosticsEngine::Error) {
if (++NumFailures == 1)
Diag(Info.getLocation(), diag::note_fixit_unfixed_error);
}
return;
}
if (!Editor.commit(commit)) {
++NumFailures;
Diag(Info.getLocation(), diag::note_fixit_failed);
return;
}
Diag(Info.getLocation(), diag::note_fixit_applied);
}
/// \brief Emit a diagnostic via the adapted diagnostic client.
void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) {
// When producing this diagnostic, we temporarily bypass ourselves,
// clear out any current diagnostic, and let the downstream client
// format the diagnostic.
Diags.setClient(Client, false);
Diags.Clear();
Diags.Report(Loc, DiagID);
Diags.setClient(this, false);
}
FixItOptions::~FixItOptions() {}

View File

@ -0,0 +1,318 @@
//===--- 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/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Config/config.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/Module.h"
#include "clang/Serialization/ModuleManager.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <utility>
using namespace clang;
//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//
std::unique_ptr<ASTConsumer>
HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (std::unique_ptr<raw_ostream> OS =
CI.createDefaultOutputFile(false, InFile))
return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
return nullptr;
}
FixItAction::FixItAction() {}
FixItAction::~FixItAction() {}
std::unique_ptr<ASTConsumer>
FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return llvm::make_unique<ASTConsumer>();
}
namespace {
class FixItRewriteInPlace : public FixItOptions {
public:
FixItRewriteInPlace() { InPlace = true; }
std::string RewriteFilename(const std::string &Filename, int &fd) override {
llvm_unreachable("don't call RewriteFilename for inplace rewrites");
}
};
class FixItActionSuffixInserter : public FixItOptions {
std::string NewSuffix;
public:
FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
: NewSuffix(std::move(NewSuffix)) {
this->FixWhatYouCan = FixWhatYouCan;
}
std::string RewriteFilename(const std::string &Filename, int &fd) override {
fd = -1;
SmallString<128> Path(Filename);
llvm::sys::path::replace_extension(Path,
NewSuffix + llvm::sys::path::extension(Path));
return Path.str();
}
};
class FixItRewriteToTemp : public FixItOptions {
public:
std::string RewriteFilename(const std::string &Filename, int &fd) override {
SmallString<128> Path;
llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
llvm::sys::path::extension(Filename).drop_front(), fd,
Path);
return Path.str();
}
};
} // end anonymous namespace
bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
if (!FEOpts.FixItSuffix.empty()) {
FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
FEOpts.FixWhatYouCan));
} else {
FixItOpts.reset(new FixItRewriteInPlace);
FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
}
Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
CI.getLangOpts(), FixItOpts.get()));
return true;
}
void FixItAction::EndSourceFileAction() {
// Otherwise rewrite all files.
Rewriter->WriteFixedFiles();
}
bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
std::vector<std::pair<std::string, std::string> > RewrittenFiles;
bool err = false;
{
const FrontendOptions &FEOpts = CI.getFrontendOpts();
std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
std::unique_ptr<FixItOptions> FixItOpts;
if (FEOpts.FixToTemporaries)
FixItOpts.reset(new FixItRewriteToTemp());
else
FixItOpts.reset(new FixItRewriteInPlace());
FixItOpts->Silent = true;
FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
CI.getLangOpts(), FixItOpts.get());
FixAction->Execute();
err = Rewriter.WriteFixedFiles(&RewrittenFiles);
FixAction->EndSourceFile();
CI.setSourceManager(nullptr);
CI.setFileManager(nullptr);
} else {
err = true;
}
}
if (err)
return false;
CI.getDiagnosticClient().clear();
CI.getDiagnostics().Reset();
PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
RewrittenFiles.begin(), RewrittenFiles.end());
PPOpts.RemappedFilesKeepOriginalName = false;
return true;
}
#if CLANG_ENABLE_OBJC_REWRITER
std::unique_ptr<ASTConsumer>
RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (std::unique_ptr<raw_ostream> OS =
CI.createDefaultOutputFile(false, InFile, "cpp")) {
if (CI.getLangOpts().ObjCRuntime.isNonFragile())
return CreateModernObjCRewriter(
InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
CI.getDiagnosticOpts().NoRewriteMacros,
(CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
CI.getLangOpts(),
CI.getDiagnosticOpts().NoRewriteMacros);
}
return nullptr;
}
#endif
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//
void RewriteMacrosAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
std::unique_ptr<raw_ostream> OS =
CI.createDefaultOutputFile(true, getCurrentFile());
if (!OS) return;
RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
}
void RewriteTestAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
std::unique_ptr<raw_ostream> OS =
CI.createDefaultOutputFile(false, getCurrentFile());
if (!OS) return;
DoRewriteTest(CI.getPreprocessor(), OS.get());
}
class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
CompilerInstance &CI;
std::weak_ptr<raw_ostream> Out;
llvm::DenseSet<const FileEntry*> Rewritten;
public:
RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
: CI(CI), Out(Out) {}
void visitModuleFile(StringRef Filename,
serialization::ModuleKind Kind) override {
auto *File = CI.getFileManager().getFile(Filename);
assert(File && "missing file for loaded module?");
// Only rewrite each module file once.
if (!Rewritten.insert(File).second)
return;
serialization::ModuleFile *MF =
CI.getModuleManager()->getModuleManager().lookup(File);
assert(File && "missing module file for loaded module?");
// Not interested in PCH / preambles.
if (!MF->isModule())
return;
auto OS = Out.lock();
assert(OS && "loaded module file after finishing rewrite action?");
(*OS) << "#pragma clang module build ";
if (isValidIdentifier(MF->ModuleName))
(*OS) << MF->ModuleName;
else {
(*OS) << '"';
OS->write_escaped(MF->ModuleName);
(*OS) << '"';
}
(*OS) << '\n';
// Rewrite the contents of the module in a separate compiler instance.
CompilerInstance Instance(CI.getPCHContainerOperations(),
&CI.getPreprocessor().getPCMCache());
Instance.setInvocation(
std::make_shared<CompilerInvocation>(CI.getInvocation()));
Instance.createDiagnostics(
new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
/*ShouldOwnClient=*/true);
Instance.getFrontendOpts().DisableFree = false;
Instance.getFrontendOpts().Inputs.clear();
Instance.getFrontendOpts().Inputs.emplace_back(
Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
Instance.getFrontendOpts().ModuleFiles.clear();
Instance.getFrontendOpts().ModuleMapFiles.clear();
// Don't recursively rewrite imports. We handle them all at the top level.
Instance.getPreprocessorOutputOpts().RewriteImports = false;
llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
RewriteIncludesAction Action;
Action.OutputStream = OS;
Instance.ExecuteAction(Action);
});
(*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
}
};
bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
if (!OutputStream) {
OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
if (!OutputStream)
return false;
}
auto &OS = *OutputStream;
// If we're preprocessing a module map, start by dumping the contents of the
// module itself before switching to the input buffer.
auto &Input = getCurrentInput();
if (Input.getKind().getFormat() == InputKind::ModuleMap) {
if (Input.isFile()) {
OS << "# 1 \"";
OS.write_escaped(Input.getFile());
OS << "\"\n";
}
getCurrentModule()->print(OS);
OS << "#pragma clang module contents\n";
}
// If we're rewriting imports, set up a listener to track when we import
// module files.
if (CI.getPreprocessorOutputOpts().RewriteImports) {
CI.createModuleManager();
CI.getModuleManager()->addListener(
llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
}
return true;
}
void RewriteIncludesAction::ExecuteAction() {
CompilerInstance &CI = getCompilerInstance();
// If we're rewriting imports, emit the module build output first rather
// than switching back and forth (potentially in the middle of a line).
if (CI.getPreprocessorOutputOpts().RewriteImports) {
std::string Buffer;
llvm::raw_string_ostream OS(Buffer);
RewriteIncludesInInput(CI.getPreprocessor(), &OS,
CI.getPreprocessorOutputOpts());
(*OutputStream) << OS.str();
} else {
RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
CI.getPreprocessorOutputOpts());
}
OutputStream.reset();
}

View File

@ -0,0 +1,93 @@
//===--- HTMLPrint.cpp - Source code -> HTML pretty-printing --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Pretty-printing of source code to HTML.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/ASTConsumers.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Functional HTML pretty-printing.
//===----------------------------------------------------------------------===//
namespace {
class HTMLPrinter : public ASTConsumer {
Rewriter R;
std::unique_ptr<raw_ostream> Out;
Preprocessor &PP;
bool SyntaxHighlight, HighlightMacros;
public:
HTMLPrinter(std::unique_ptr<raw_ostream> OS, Preprocessor &pp,
bool _SyntaxHighlight, bool _HighlightMacros)
: Out(std::move(OS)), PP(pp), SyntaxHighlight(_SyntaxHighlight),
HighlightMacros(_HighlightMacros) {}
void Initialize(ASTContext &context) override;
void HandleTranslationUnit(ASTContext &Ctx) override;
};
}
std::unique_ptr<ASTConsumer>
clang::CreateHTMLPrinter(std::unique_ptr<raw_ostream> OS, Preprocessor &PP,
bool SyntaxHighlight, bool HighlightMacros) {
return llvm::make_unique<HTMLPrinter>(std::move(OS), PP, SyntaxHighlight,
HighlightMacros);
}
void HTMLPrinter::Initialize(ASTContext &context) {
R.setSourceMgr(context.getSourceManager(), context.getLangOpts());
}
void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) {
if (PP.getDiagnostics().hasErrorOccurred())
return;
// Format the file.
FileID FID = R.getSourceMgr().getMainFileID();
const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID);
StringRef Name;
// In some cases, in particular the case where the input is from stdin,
// there is no entry. Fall back to the memory buffer for a name in those
// cases.
if (Entry)
Name = Entry->getName();
else
Name = R.getSourceMgr().getBuffer(FID)->getBufferIdentifier();
html::AddLineNumbers(R, FID);
html::AddHeaderFooterInternalBuiltinCSS(R, FID, Name);
// If we have a preprocessor, relex the file and syntax highlight.
// We might not have a preprocessor if we come from a deserialized AST file,
// for example.
if (SyntaxHighlight) html::SyntaxHighlight(R, FID, PP);
if (HighlightMacros) html::HighlightMacros(R, FID, PP);
html::EscapeText(R, FID, false, true);
// Emit the HTML.
const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID);
char *Buffer = (char*)malloc(RewriteBuf.size());
std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer);
Out->write(Buffer, RewriteBuf.size());
free(Buffer);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This code rewrites macro invocations into their expansions. This gives you
// a macro expanded file that retains comments and #includes.
//
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <memory>
using namespace clang;
/// isSameToken - Return true if the two specified tokens start have the same
/// content.
static bool isSameToken(Token &RawTok, Token &PPTok) {
// If two tokens have the same kind and the same identifier info, they are
// obviously the same.
if (PPTok.getKind() == RawTok.getKind() &&
PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
return true;
// Otherwise, if they are different but have the same identifier info, they
// are also considered to be the same. This allows keywords and raw lexed
// identifiers with the same name to be treated the same.
if (PPTok.getIdentifierInfo() &&
PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo())
return true;
return false;
}
/// GetNextRawTok - Return the next raw token in the stream, skipping over
/// comments if ReturnComment is false.
static const Token &GetNextRawTok(const std::vector<Token> &RawTokens,
unsigned &CurTok, bool ReturnComment) {
assert(CurTok < RawTokens.size() && "Overran eof!");
// If the client doesn't want comments and we have one, skip it.
if (!ReturnComment && RawTokens[CurTok].is(tok::comment))
++CurTok;
return RawTokens[CurTok++];
}
/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into
/// the specified vector.
static void LexRawTokensFromMainFile(Preprocessor &PP,
std::vector<Token> &RawTokens) {
SourceManager &SM = PP.getSourceManager();
// Create a lexer to lex all the tokens of the main file in raw mode. Even
// though it is in raw mode, it will not return comments.
const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
// Switch on comment lexing because we really do want them.
RawLex.SetCommentRetentionState(true);
Token RawTok;
do {
RawLex.LexFromRawLexer(RawTok);
// If we have an identifier with no identifier info for our raw token, look
// up the identifier info. This is important for equality comparison of
// identifier tokens.
if (RawTok.is(tok::raw_identifier))
PP.LookUpIdentifierInfo(RawTok);
RawTokens.push_back(RawTok);
} while (RawTok.isNot(tok::eof));
}
/// RewriteMacrosInInput - Implement -rewrite-macros mode.
void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) {
SourceManager &SM = PP.getSourceManager();
Rewriter Rewrite;
Rewrite.setSourceMgr(SM, PP.getLangOpts());
RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID());
std::vector<Token> RawTokens;
LexRawTokensFromMainFile(PP, RawTokens);
unsigned CurRawTok = 0;
Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
// Get the first preprocessing token.
PP.EnterMainSourceFile();
Token PPTok;
PP.Lex(PPTok);
// Preprocess the input file in parallel with raw lexing the main file. Ignore
// all tokens that are preprocessed from a file other than the main file (e.g.
// a header). If we see tokens that are in the preprocessed file but not the
// lexed file, we have a macro expansion. If we see tokens in the lexed file
// that aren't in the preprocessed view, we have macros that expand to no
// tokens, or macro arguments etc.
while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) {
SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation());
// If PPTok is from a different source file, ignore it.
if (!SM.isWrittenInMainFile(PPLoc)) {
PP.Lex(PPTok);
continue;
}
// If the raw file hits a preprocessor directive, they will be extra tokens
// in the raw file that don't exist in the preprocsesed file. However, we
// choose to preserve them in the output file and otherwise handle them
// specially.
if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) {
// If this is a #warning directive or #pragma mark (GNU extensions),
// comment the line out.
if (RawTokens[CurRawTok].is(tok::identifier)) {
const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo();
if (II->getName() == "warning") {
// Comment out #warning.
RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//");
} else if (II->getName() == "pragma" &&
RawTokens[CurRawTok+1].is(tok::identifier) &&
(RawTokens[CurRawTok+1].getIdentifierInfo()->getName() ==
"mark")) {
// Comment out #pragma mark.
RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//");
}
}
// Otherwise, if this is a #include or some other directive, just leave it
// in the file by skipping over the line.
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof))
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
continue;
}
// Okay, both tokens are from the same file. Get their offsets from the
// start of the file.
unsigned PPOffs = SM.getFileOffset(PPLoc);
unsigned RawOffs = SM.getFileOffset(RawTok.getLocation());
// If the offsets are the same and the token kind is the same, ignore them.
if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) {
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
PP.Lex(PPTok);
continue;
}
// If the PP token is farther along than the raw token, something was
// deleted. Comment out the raw token.
if (RawOffs <= PPOffs) {
// Comment out a whole run of tokens instead of bracketing each one with
// comments. Add a leading space if RawTok didn't have one.
bool HasSpace = RawTok.hasLeadingSpace();
RB.InsertTextAfter(RawOffs, &" /*"[HasSpace]);
unsigned EndPos;
do {
EndPos = RawOffs+RawTok.getLength();
RawTok = GetNextRawTok(RawTokens, CurRawTok, true);
RawOffs = SM.getFileOffset(RawTok.getLocation());
if (RawTok.is(tok::comment)) {
// Skip past the comment.
RawTok = GetNextRawTok(RawTokens, CurRawTok, false);
break;
}
} while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() &&
(PPOffs != RawOffs || !isSameToken(RawTok, PPTok)));
RB.InsertTextBefore(EndPos, "*/");
continue;
}
// Otherwise, there was a replacement an expansion. Insert the new token
// in the output buffer. Insert the whole run of new tokens at once to get
// them in the right order.
unsigned InsertPos = PPOffs;
std::string Expansion;
while (PPOffs < RawOffs) {
Expansion += ' ' + PP.getSpelling(PPTok);
PP.Lex(PPTok);
PPLoc = SM.getExpansionLoc(PPTok.getLocation());
PPOffs = SM.getFileOffset(PPLoc);
}
Expansion += ' ';
RB.InsertTextBefore(InsertPos, Expansion);
}
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
// we are done.
if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(SM.getMainFileID())) {
//printf("Changed:\n");
*OS << std::string(RewriteBuf->begin(), RewriteBuf->end());
} else {
fprintf(stderr, "No changes\n");
}
OS->flush();
}

View File

@ -0,0 +1 @@
1954b24aedad3bf23148327b59a17a532c714a44

View File

@ -0,0 +1 @@
096b81bc3f08cbd62d87bf9b09e0ad667b076e1f

View File

@ -0,0 +1,39 @@
//===--- RewriteTest.cpp - Rewriter playground ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is a testbed.
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/TokenRewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/Support/raw_ostream.h"
void clang::DoRewriteTest(Preprocessor &PP, raw_ostream *OS) {
SourceManager &SM = PP.getSourceManager();
const LangOptions &LangOpts = PP.getLangOpts();
TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts);
// Throw <i> </i> tags around comments.
for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
E = Rewriter.token_end(); I != E; ++I) {
if (I->isNot(tok::comment)) continue;
Rewriter.AddTokenBefore(I, "<i>");
Rewriter.AddTokenAfter(I, "</i>");
}
// Print out the output.
for (TokenRewriter::token_iterator I = Rewriter.token_begin(),
E = Rewriter.token_end(); I != E; ++I)
*OS << PP.getSpelling(*I);
}