diff --git a/clang/include/clang/3C/RewriteUtils.h b/clang/include/clang/3C/RewriteUtils.h index 5fd4dc8de7c6..0f312418bf5e 100644 --- a/clang/include/clang/3C/RewriteUtils.h +++ b/clang/include/clang/3C/RewriteUtils.h @@ -159,6 +159,12 @@ class RewriteConsumer : public ASTConsumer { static std::set EmittedDiagnostics; void emitRootCauseDiagnostics(ASTContext &Context); + + // Hack to avoid printing the main file to stdout multiple times in the edge + // case of a compilation database containing multiple translation units for + // the main file + // (https://github.com/correctcomputation/checkedc-clang/issues/374#issuecomment-893612654). + bool StdoutModeEmittedMainFile = false; }; bool canRewrite(Rewriter &R, const SourceRange &SR); diff --git a/clang/lib/3C/RewriteUtils.cpp b/clang/lib/3C/RewriteUtils.cpp index b9eb8169b8e2..31656e9c80da 100644 --- a/clang/lib/3C/RewriteUtils.cpp +++ b/clang/lib/3C/RewriteUtils.cpp @@ -120,12 +120,11 @@ void rewriteSourceRange(Rewriter &R, const CharSourceRange &Range, } } -static void emit(Rewriter &R, ASTContext &C) { +static void emit(Rewriter &R, ASTContext &C, bool &StdoutModeEmittedMainFile) { if (Verbose) errs() << "Writing files out\n"; bool StdoutMode = (OutputPostfix == "-" && OutputDir.empty()); - bool StdoutModeSawMainFile = false; SourceManager &SM = C.getSourceManager(); // Iterate over each modified rewrite buffer. for (auto Buffer = R.buffer_begin(); Buffer != R.buffer_end(); ++Buffer) { @@ -226,9 +225,15 @@ static void emit(Rewriter &R, ASTContext &C) { if (StdoutMode) { if (Buffer->first == SM.getMainFileID()) { - // This is the new version of the main file. Print it to stdout. - Buffer->second.write(outs()); - StdoutModeSawMainFile = true; + // This is the new version of the main file. Print it to stdout, + // except in the edge case where we have a compilation database with + // multiple translation units with the same main file and we already + // emitted a copy of the main file for a previous translation unit + // (https://github.com/correctcomputation/checkedc-clang/issues/374#issuecomment-893612654). + if (!StdoutModeEmittedMainFile) { + Buffer->second.write(outs()); + StdoutModeEmittedMainFile = true; + } } else { unsigned ID = DE.getCustomDiagID( UnwritableChangeDiagnosticLevel, @@ -300,9 +305,10 @@ static void emit(Rewriter &R, ASTContext &C) { } } - if (StdoutMode && !StdoutModeSawMainFile) { + if (StdoutMode && !StdoutModeEmittedMainFile) { // The main file is unchanged. Write out its original content. outs() << SM.getBufferOrFake(SM.getMainFileID()).getBuffer(); + StdoutModeEmittedMainFile = true; } } @@ -632,7 +638,7 @@ void RewriteConsumer::HandleTranslationUnit(ASTContext &Context) { } // Output files. - emit(R, Context); + emit(R, Context, StdoutModeEmittedMainFile); Info.getPerfStats().endRewritingTime(); diff --git a/clang/test/3C/multiple_tu.c b/clang/test/3C/multiple_tu.c index d7fc64f5145c..f56cb54e6945 100644 --- a/clang/test/3C/multiple_tu.c +++ b/clang/test/3C/multiple_tu.c @@ -13,10 +13,22 @@ // present in the root cause statistics json output. The json is used to // generate the output for 3c-wrap root_cause, so the error appeared there as well. +// Furthermore, in stdout mode, if the main file was processed twice, the +// rewritten version was printed to stdout twice +// (https://github.com/correctcomputation/checkedc-clang/issues/374#issuecomment-893612654). +// Check that this doesn't happen any more. + _Itype_for_any(T) void my_free(void *pointer : itype(_Array_ptr) byte_count(0)); void foo() { + //CHECK: {{^}}void foo() { int *a; my_free(a); //CHECK: my_free(a); } + +// Make sure the file does not get printed to stdout a second time. Since +// -match-full-lines does not apply to CHECK-NOT, the {{^}} is needed to anchor +// the match to the beginning of the line and prevent the CHECK-NOT from +// matching itself. +//CHECK-NOT: {{^}}void foo() {