[cfe-commits] multifile fixits
Nick Lewycky
nlewycky at google.com
Wed Apr 14 23:48:31 PDT 2010
On 14 April 2010 07:44, Douglas Gregor <dgregor at apple.com> wrote:
>
> On Apr 9, 2010, at 7:24 PM, Nick Lewycky wrote:
>
> Currently the fixit system runs in one of two modes, either fix the
> particular problems specified through the -fixit-at parameter, or fix only
> the problems found in the main file. As a bonus bug, in the fix-all mode,
> clang's diagnostic output will claim that it's applied changes to files that
> it isn't actually touching.
>
> This patch makes fixits apply to all files when no -fixit-at or -o flag is
> specified. For compatibility with our tests, clang -fixit -o foo will still
> only output the main file (but see FIXME in patch). This also exposes the
> fileid's out the FixItRewriter so that users can write their own frontend
> action which chooses file names other than the default foo.fixit.cc.
>
>
> ---
> /tmp/g4-68652/cache/depot/google3/third_party/llvm/trunk/tools/clang/lib/Frontend/FixItRewriter.cpp#4 2010-04-08
> 23:10:18.000000000 -0700
> +++
> /home/nlewycky/llvm-ftw1/google3/third_party/llvm/trunk/tools/clang/lib/Frontend/FixItRewriter.cpp 2010-04-09
> 17:17:26.741262000 -0700
> @@ -14,6 +14,8 @@
>
> //===----------------------------------------------------------------------===//
>
> #include "clang/Frontend/FixItRewriter.h"
> +#include "clang/Basic/FileManager.h"
> +#include "clang/Basic/SourceLocation.h"
> #include "clang/Basic/SourceManager.h"
> #include "clang/Frontend/FrontendDiagnostic.h"
> #include "llvm/Support/raw_ostream.h"
> @@ -34,47 +36,41 @@
> Diags.setClient(Client);
> }
>
> -bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
> - const std::string &OutFileName) {
> +bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream *OS) {
> + const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID);
> + if (!RewriteBuf) return true;
> + *OS << std::string(RewriteBuf->begin(), RewriteBuf->end());
> + OS->flush();
> + return false;
> +}
>
> Please use OS->write() instead of forming a temporary string.
>
No can do. It's not backed by contiguous storage being a btree-string and
there's no existing API to print these things without an std::string
temporary. In a future patch I'll add a print(raw_ostream&) method to
RewriteBuffer or one of its base classes, with the inefficient
implementation and a FIXME to make it more awesome.
> Also, shouldn't the raw_ostream be a reference parameter rather than a
> pointer parameter, since it can't be NULL anyway?
>
Done.
> +
> +bool FixItRewriter::WriteFixedFiles() {
> if (NumFailures > 0) {
> Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
> return true;
> }
>
> - llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
> - llvm::raw_ostream *OutFile;
> - if (!OutFileName.empty()) {
> - std::string Err;
> - OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err,
> - llvm::raw_fd_ostream::F_Binary);
> - OwnedStream.reset(OutFile);
> - } else if (InFileName == "-") {
> - OutFile = &llvm::outs();
> - } else {
> - llvm::sys::Path Path(InFileName);
> + for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
> + const FileEntry *Entry =
> Rewrite.getSourceMgr().getFileEntryForID(I->first);
> + llvm::sys::Path Path(Entry->getName());
> std::string Suffix = Path.getSuffix();
> Path.eraseSuffix();
> Path.appendSuffix("fixit." + Suffix);
> std::string Err;
> - OutFile = new llvm::raw_fd_ostream(Path.c_str(), Err,
> - llvm::raw_fd_ostream::F_Binary);
> - OwnedStream.reset(OutFile);
> - }
> + llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(Path.c_str(), Err,
> +
> llvm::raw_fd_ostream::F_Binary);
>
> The raw_fd_ostream could/should be stack-allocated.
>
Done.
> Okay, so this will overwriter the files in place. We should be prepared for
> the write to fail, e.g., if the source file is read-only (and emit a
> reasonable diagnostic when it does).
>
> - FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
> - if (const RewriteBuffer *RewriteBuf =
> - Rewrite.getRewriteBufferFor(MainFileID)) {
> - *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
> - } else {
> - Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged);
> + RewriteBuffer &RewriteBuf = I->second;
> + *OS << std::string(RewriteBuf.begin(), RewriteBuf.end());
> + OS->flush();
> + delete OS;
>
> Same OS.write() comment as above.
>
> ====
> //depot/google3/third_party/llvm/trunk/tools/clang/lib/Frontend/FrontendActions.cpp#7
> -
> /home/nlewycky/llvm-ftw1/google3/third_party/llvm/trunk/tools/clang/lib/Frontend/FrontendActions.cpp
> ====
> ---
> /tmp/g4-68652/cache/depot/google3/third_party/llvm/trunk/tools/clang/lib/Frontend/FrontendActions.cpp#7 2010-04-08
> 21:49:14.000000000 -0700
> +++
> /home/nlewycky/llvm-ftw1/google3/third_party/llvm/trunk/tools/clang/lib/Frontend/FrontendActions.cpp 2010-04-09
> 15:59:12.323217000 -0700
> @@ -139,6 +139,23 @@
> FixItRewrite.addFixItLocation(Requested);
> }
>
> + const std::string &OutputFile = CI.getFrontendOpts().OutputFile;
> + if (Locs.empty() && !OutputFile.empty()) {
> + // FIXME: we will issue "FIX-IT applied suggested code changes" for
> every
> + // input, but only the main file will actually be rewritten.
> + const std::vector<std::pair<FrontendOptions::InputKind, std::string> >
> &Inputs =
> + CI.getFrontendOpts().Inputs;
> + for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
> + const FileEntry *File =
> CI.getFileManager().getFile(Inputs[i].second);
> + assert(File && "Input file not found in FileManager");
> + RequestedSourceLocation Requested;
> + Requested.File = File;
> + Requested.Line = 0;
> + Requested.Column = 0;
> + FixItRewrite.addFixItLocation(Requested);
> + }
> + }
> +
> return true;
> }
>
> Thanks for maintaining the current interface. Now, I think we should change
> that interface :)
>
> The "only fix the main file" approach was me being paranoid when fix-its
> first went it. I think the right answer now is for -fixit to always apply
> changes to all of the files (in place), and to allow a file name suffix,
> e.g.,
>
> 1) -fixit changes files in-place
> 2) -fixit=suffix puts the changes for any file "foo.c" into "foosuffix.c";
> we'll mainly use this for testing, I think.
>
> At this point, I trust fix-its enough that I'd like to add -fixit to my
> normal Clang build. I'm not worried about it because we should only write
> out the changed files if *all* errors have fix-its that were properly
> applied, so we only end up changing the source code when our changes
> produced a program that actually compiles.
>
Yes, this sounds like the right way to go forward. I'll be happy to rip out
the -fixit-at logic!
Nick
>
> Anyway, thank you for working on this! Please feel free to go ahead and
> commit with the few changes requested above; we can tackle the interface
> change separately.
>
> - Doug
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100414/e9d70897/attachment.html>
More information about the cfe-commits
mailing list