Skip to content

Commit c5d22c2

Browse files
committed
[clang-tidy] Fixed clang-tidy rewriter not properly handling symlinks
Rewriter would not properly fix files if they were symlinked and using --fix with clang-tidy would overwrite the symlink with the corrections rather than the file. With these changes the Rewriter now properly resolves the symlink before applying the fixes. Fixes #60845
1 parent 30f44c9 commit c5d22c2

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ Improvements to clang-query
8888
Improvements to clang-tidy
8989
--------------------------
9090

91+
- Improved `--fix` to properly apply corrections on files that are symlinked.
92+
9193
New checks
9294
^^^^^^^^^^
9395

clang/lib/Rewrite/Rewriter.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/Rewrite/Core/Rewriter.h"
1515
#include "clang/Basic/Diagnostic.h"
1616
#include "clang/Basic/DiagnosticIDs.h"
17+
#include "clang/Basic/FileEntry.h"
1718
#include "clang/Basic/SourceLocation.h"
1819
#include "clang/Basic/SourceManager.h"
1920
#include "clang/Lex/Lexer.h"
@@ -317,16 +318,19 @@ bool Rewriter::overwriteChangedFiles() {
317318
unsigned OverwriteFailure = Diag.getCustomDiagID(
318319
DiagnosticsEngine::Error, "unable to overwrite file %0: %1");
319320
for (buffer_iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
320-
OptionalFileEntryRef Entry = getSourceMgr().getFileEntryRefForID(I->first);
321-
llvm::SmallString<128> Path(Entry->getName());
322-
getSourceMgr().getFileManager().makeAbsolutePath(Path);
323-
if (auto Error = llvm::writeToOutput(Path, [&](llvm::raw_ostream &OS) {
324-
I->second.write(OS);
325-
return llvm::Error::success();
326-
})) {
327-
Diag.Report(OverwriteFailure)
328-
<< Entry->getName() << llvm::toString(std::move(Error));
329-
AllWritten = false;
321+
if (OptionalFileEntryRef fileEntry =
322+
getSourceMgr().getFileEntryRefForID(I->first)) {
323+
llvm::StringRef FileName =
324+
getSourceMgr().getFileManager().getCanonicalName(*fileEntry);
325+
if (auto Error =
326+
llvm::writeToOutput(FileName, [&](llvm::raw_ostream &OS) {
327+
I->second.write(OS);
328+
return llvm::Error::success();
329+
})) {
330+
Diag.Report(OverwriteFailure)
331+
<< FileName << llvm::toString(std::move(Error));
332+
AllWritten = false;
333+
}
330334
}
331335
}
332336
return !AllWritten;

clang/unittests/libclang/LibclangTest.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/Support/raw_ostream.h"
1717
#include "gtest/gtest.h"
1818
#include <cstring>
19+
#include <filesystem>
1920
#include <fstream>
2021
#include <functional>
2122
#include <map>
@@ -1410,3 +1411,27 @@ TEST_F(LibclangRewriteTest, RewriteRemove) {
14101411
ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
14111412
EXPECT_EQ(getFileContent(Filename), "int () { return 0; }");
14121413
}
1414+
1415+
TEST_F(LibclangRewriteTest, Symlink) {
1416+
std::filesystem::path Symlink = "link.cpp";
1417+
std::filesystem::create_symlink(Filename, Symlink);
1418+
ASSERT_TRUE(std::filesystem::exists(Symlink));
1419+
FilesAndDirsToRemove.emplace(Symlink);
1420+
1421+
CXTranslationUnit SymTu = clang_parseTranslationUnit(
1422+
Index, Symlink.c_str(), nullptr, 0, nullptr, 0, TUFlags);
1423+
CXFile SymlinkFile = clang_getFile(SymTu, Symlink.c_str());
1424+
CXRewriter SymRew = clang_CXRewriter_create(SymTu);
1425+
1426+
CXSourceLocation B = clang_getLocation(SymTu, SymlinkFile, 1, 5);
1427+
CXSourceLocation E = clang_getLocation(SymTu, SymlinkFile, 1, 9);
1428+
CXSourceRange Rng = clang_getRange(B, E);
1429+
1430+
clang_CXRewriter_removeText(SymRew, Rng);
1431+
1432+
ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(SymRew), 0);
1433+
EXPECT_EQ(getFileContent(Filename), "int () { return 0; }");
1434+
EXPECT_TRUE(std::filesystem::is_symlink(Symlink));
1435+
1436+
clang_CXRewriter_dispose(SymRew);
1437+
}

0 commit comments

Comments
 (0)