diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -39,14 +39,35 @@ } } +llvm::Optional firstLocAfterNewLine(SourceLocation Loc, + SourceManager &SM) { + bool Invalid; + const char *TextAfter = SM.getCharacterData(Loc, &Invalid); + if (Invalid) { + return llvm::None; + } + size_t Offset = std::strcspn(TextAfter, "\n"); + return Loc.getLocWithOffset(TextAfter[Offset] == '\0' ? Offset : Offset + 1); +} + void recordRemoval(const DeclStmt &Stmt, ASTContext &Context, DiagnosticBuilder &Diagnostic) { - // Attempt to remove the whole line until the next non-comment token. - auto Tok = utils::lexer::findNextTokenSkippingComments( - Stmt.getEndLoc(), Context.getSourceManager(), Context.getLangOpts()); - if (Tok) { - Diagnostic << FixItHint::CreateRemoval(SourceRange( - Stmt.getBeginLoc(), Tok->getLocation().getLocWithOffset(-1))); + auto &SM = Context.getSourceManager(); + // Attempt to remove trailing comments as well. + auto Tok = utils::lexer::findNextTokenSkippingComments(Stmt.getEndLoc(), SM, + Context.getLangOpts()); + llvm::Optional PastNewLine = + firstLocAfterNewLine(Stmt.getEndLoc(), SM); + if (Tok && PastNewLine) { + auto BeforeFirstTokenAfterComment = Tok->getLocation().getLocWithOffset(-1); + // Remove until the end of the line or the end of a trailing comment which + // ever comes first. + auto End = + SM.isBeforeInTranslationUnit(*PastNewLine, BeforeFirstTokenAfterComment) + ? *PastNewLine + : BeforeFirstTokenAfterComment; + Diagnostic << FixItHint::CreateRemoval( + SourceRange(Stmt.getBeginLoc(), End)); } else { Diagnostic << FixItHint::CreateRemoval(Stmt.getSourceRange()); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance-unnecessary-copy-initialization.cpp @@ -596,8 +596,15 @@ // CHECK-FIXES: int i = 0; // Foo bar. auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment. // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the variable 'TrailingCommentRemoved' is copy-constructed from a const reference but is never used; - // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); // Trailing comment. + // CHECK-FIXES-NOT: auto TrailingCommentRemoved = ExpensiveTypeReference(); + // CHECK-FIXES-NOT: // Trailing comment. // clang-format on + + auto UnusedAndUnnecessary = ExpensiveTypeReference(); + // Comments on a new line should not be deleted. + // CHECK-MESSAGES: [[@LINE-2]]:8: warning: the variable 'UnusedAndUnnecessary' is copy-constructed + // CHECK-FIXES-NOT: auto UnusedAndUnnecessary = ExpensiveTypeReference(); + // CHECK-FIXES: // Comments on a new line should not be deleted. } void negativeloopedOverObjectIsModified() {