[clangd] Do not collect macros when clang-tidy checks call into the preprocessor (#106329)

Fixes https://github.com/llvm/llvm-project/issues/99617
This commit is contained in:
Nathan Ridge
2024-08-28 23:37:01 -04:00
committed by GitHub
parent 121fb2c2cc
commit ee6961dbf1
4 changed files with 33 additions and 1 deletions

View File

@@ -32,6 +32,7 @@ void CollectMainFileMacros::add(const Token &MacroNameTok, const MacroInfo *MI,
if (Loc.isInvalid() || Loc.isMacroID())
return;
assert(isInsideMainFile(Loc, SM));
auto Name = MacroNameTok.getIdentifierInfo()->getName();
Out.Names.insert(Name);
size_t Start = SM.getFileOffset(Loc);

View File

@@ -82,6 +82,14 @@ public:
void SourceRangeSkipped(SourceRange R, SourceLocation EndifLoc) override;
// Called when the AST build is done to disable further recording
// of macros by this class. This is needed because some clang-tidy
// checks can trigger PP callbacks by calling directly into the
// preprocessor. Such calls are not interleaved with FileChanged()
// in the expected way, leading this class to erroneously process
// macros that are not in the main file.
void doneParse() { InMainFile = false; }
private:
void add(const Token &MacroNameTok, const MacroInfo *MI,
bool IsDefinition = false, bool InConditionalDirective = false);

View File

@@ -688,7 +688,9 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
Marks = Patch->marks();
}
auto &PP = Clang->getPreprocessor();
PP.addPPCallbacks(std::make_unique<CollectMainFileMacros>(PP, Macros));
auto MacroCollector = std::make_unique<CollectMainFileMacros>(PP, Macros);
auto *MacroCollectorPtr = MacroCollector.get(); // so we can call doneParse()
PP.addPPCallbacks(std::move(MacroCollector));
PP.addPPCallbacks(
collectPragmaMarksCallback(Clang->getSourceManager(), Marks));
@@ -709,6 +711,10 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
log("Execute() failed when building AST for {0}: {1}", MainInput.getFile(),
toString(std::move(Err)));
// Disable the macro collector for the remainder of this function, e.g.
// clang-tidy checkers.
MacroCollectorPtr->doneParse();
// We have to consume the tokens before running clang-tidy to avoid collecting
// tokens from running the preprocessor inside the checks (only
// modernize-use-trailing-return-type does that today).

View File

@@ -940,6 +940,23 @@ TEST(DiagnosticTest, ClangTidySelfContainedDiagsFormatting) {
withFix(equalToFix(ExpectedFix2))))));
}
TEST(DiagnosticsTest, ClangTidyCallingIntoPreprocessor) {
std::string Main = R"cpp(
extern "C" {
#include "b.h"
}
)cpp";
std::string Header = R"cpp(
#define EXTERN extern
EXTERN int waldo();
)cpp";
auto TU = TestTU::withCode(Main);
TU.AdditionalFiles["b.h"] = Header;
TU.ClangTidyProvider = addTidyChecks("modernize-use-trailing-return-type");
// Check that no assertion failures occur during the build
TU.build();
}
TEST(DiagnosticsTest, Preprocessor) {
// This looks like a preamble, but there's an #else in the middle!
// Check that: