[clang-tidy] Fix broken HeaderFilterRegex when read from config file (#133582)
PR https://github.com/llvm/llvm-project/pull/91400 broke the usage of HeaderFilterRegex via config file, because it is now created at a different point in the execution and leads to a different value. The result of that is that using HeaderFilterRegex only in the config file does NOT work, in other words clang-tidy stops triggering warnings on header files, thereby losing a lot of coverage. This patch reverts the logic so that the header filter is created upon calling the getHeaderFilter() function. Additionally, this patch adds 2 unit tests to prevent regressions in the future: - One of them, "simple", tests the most basic use case with a single top-level .clang-tidy file. - The second one, "inheritance", demonstrates that the subfolder only gets warnings from headers within it, and not from parent headers. Fixes #118009 Fixes #121969 Fixes #133453 Co-authored-by: Carlos Gálvez <carlos.galvez@zenseact.com>
This commit is contained in:
parent
e1aaee7ea2
commit
6333fa5160
@ -311,18 +311,7 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(
|
||||
: Context(Ctx), ExternalDiagEngine(ExternalDiagEngine),
|
||||
RemoveIncompatibleErrors(RemoveIncompatibleErrors),
|
||||
GetFixesFromNotes(GetFixesFromNotes),
|
||||
EnableNolintBlocks(EnableNolintBlocks) {
|
||||
|
||||
if (Context.getOptions().HeaderFilterRegex &&
|
||||
!Context.getOptions().HeaderFilterRegex->empty())
|
||||
HeaderFilter =
|
||||
std::make_unique<llvm::Regex>(*Context.getOptions().HeaderFilterRegex);
|
||||
|
||||
if (Context.getOptions().ExcludeHeaderFilterRegex &&
|
||||
!Context.getOptions().ExcludeHeaderFilterRegex->empty())
|
||||
ExcludeHeaderFilter = std::make_unique<llvm::Regex>(
|
||||
*Context.getOptions().ExcludeHeaderFilterRegex);
|
||||
}
|
||||
EnableNolintBlocks(EnableNolintBlocks) {}
|
||||
|
||||
void ClangTidyDiagnosticConsumer::finalizeLastError() {
|
||||
if (!Errors.empty()) {
|
||||
@ -571,17 +560,30 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location,
|
||||
}
|
||||
|
||||
StringRef FileName(File->getName());
|
||||
LastErrorRelatesToUserCode =
|
||||
LastErrorRelatesToUserCode || Sources.isInMainFile(Location) ||
|
||||
(HeaderFilter &&
|
||||
(HeaderFilter->match(FileName) &&
|
||||
!(ExcludeHeaderFilter && ExcludeHeaderFilter->match(FileName))));
|
||||
LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
|
||||
Sources.isInMainFile(Location) ||
|
||||
(getHeaderFilter()->match(FileName) &&
|
||||
!getExcludeHeaderFilter()->match(FileName));
|
||||
|
||||
unsigned LineNumber = Sources.getExpansionLineNumber(Location);
|
||||
LastErrorPassesLineFilter =
|
||||
LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
|
||||
}
|
||||
|
||||
llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() {
|
||||
if (!HeaderFilter)
|
||||
HeaderFilter =
|
||||
std::make_unique<llvm::Regex>(*Context.getOptions().HeaderFilterRegex);
|
||||
return HeaderFilter.get();
|
||||
}
|
||||
|
||||
llvm::Regex *ClangTidyDiagnosticConsumer::getExcludeHeaderFilter() {
|
||||
if (!ExcludeHeaderFilter)
|
||||
ExcludeHeaderFilter = std::make_unique<llvm::Regex>(
|
||||
*Context.getOptions().ExcludeHeaderFilterRegex);
|
||||
return ExcludeHeaderFilter.get();
|
||||
}
|
||||
|
||||
void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() {
|
||||
// Each error is modelled as the set of intervals in which it applies
|
||||
// replacements. To detect overlapping replacements, we use a sweep line
|
||||
|
@ -302,6 +302,10 @@ private:
|
||||
/// context.
|
||||
llvm::Regex *getHeaderFilter();
|
||||
|
||||
/// Returns the \c ExcludeHeaderFilter constructed for the options set in the
|
||||
/// context.
|
||||
llvm::Regex *getExcludeHeaderFilter();
|
||||
|
||||
/// Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
|
||||
/// according to the diagnostic \p Location.
|
||||
void checkFilters(SourceLocation Location, const SourceManager &Sources);
|
||||
|
@ -194,8 +194,8 @@ ClangTidyOptions ClangTidyOptions::getDefaults() {
|
||||
Options.WarningsAsErrors = "";
|
||||
Options.HeaderFileExtensions = {"", "h", "hh", "hpp", "hxx"};
|
||||
Options.ImplementationFileExtensions = {"c", "cc", "cpp", "cxx"};
|
||||
Options.HeaderFilterRegex = std::nullopt;
|
||||
Options.ExcludeHeaderFilterRegex = std::nullopt;
|
||||
Options.HeaderFilterRegex = "";
|
||||
Options.ExcludeHeaderFilterRegex = "";
|
||||
Options.SystemHeaders = false;
|
||||
Options.FormatStyle = "none";
|
||||
Options.User = std::nullopt;
|
||||
|
@ -94,6 +94,9 @@ Improvements to clang-tidy
|
||||
- Improved :program:`clang-tidy-diff.py` script. Add the `-warnings-as-errors`
|
||||
argument to treat warnings as errors.
|
||||
|
||||
- Fixed bug in :program:`clang-tidy` by which `HeaderFilterRegex` did not take
|
||||
effect when passed via the `.clang-tidy` file.
|
||||
|
||||
New checks
|
||||
^^^^^^^^^^
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
HeaderFilterRegex: '.*'
|
@ -0,0 +1,3 @@
|
||||
// RUN: clang-tidy -checks=-*,google-explicit-constructor %s 2>&1 | FileCheck %s
|
||||
#include "foo.h"
|
||||
// CHECK: foo.h:1:12: warning: single-argument constructors must be marked explicit
|
@ -0,0 +1 @@
|
||||
struct X { X(int); };
|
@ -0,0 +1,2 @@
|
||||
InheritParentConfig: true
|
||||
HeaderFilterRegex: 'subfolder/.*'
|
@ -0,0 +1,8 @@
|
||||
// shell is required for the "dirname" command
|
||||
// REQUIRES: shell
|
||||
// RUN: clang-tidy -checks=-*,google-explicit-constructor %s -- -I "$(dirname %S)" 2>&1 | FileCheck %s
|
||||
#include "foo.h"
|
||||
// CHECK-NOT: foo.h:1:12: warning: single-argument constructors must be marked explicit
|
||||
|
||||
#include "bar.h"
|
||||
// CHECK: bar.h:1:13: warning: single-argument constructors must be marked explicit
|
@ -0,0 +1 @@
|
||||
struct XX { XX(int); };
|
@ -0,0 +1 @@
|
||||
HeaderFilterRegex: '.*'
|
@ -0,0 +1,3 @@
|
||||
// RUN: clang-tidy -checks=-*,google-explicit-constructor %s 2>&1 | FileCheck %s
|
||||
#include "foo.h"
|
||||
// CHECK: foo.h:1:12: warning: single-argument constructors must be marked explicit
|
@ -0,0 +1 @@
|
||||
struct X { X(int); };
|
Loading…
x
Reference in New Issue
Block a user