diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h @@ -106,6 +106,10 @@ /// Add extra compilation arguments to the start of the list. llvm::Optional ExtraArgsBefore; + + /// Config flag for FileOptionsProvider to also include config from parent + /// dir. + llvm::Optional InheritParentConfig; }; /// Abstract interface for retrieving various ClangTidy options. diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -92,6 +92,7 @@ IO.mapOptional("CheckOptions", NOpts->Options); IO.mapOptional("ExtraArgs", Options.ExtraArgs); IO.mapOptional("ExtraArgsBefore", Options.ExtraArgsBefore); + IO.mapOptional("InheritParentConfig", Options.InheritParentConfig); } }; @@ -237,6 +238,7 @@ DefaultOptionsProvider::getRawOptions(AbsoluteFilePath.str()); OptionsSource CommandLineOptions(OverrideOptions, OptionsSourceTypeCheckCommandLineOption); + size_t FirstFileConfig = RawOptions.size(); // Look for a suitable configuration file in all parent directories of the // file. Start with the immediate parent directory and move up. StringRef Path = llvm::sys::path::parent_path(AbsoluteFilePath.str()); @@ -256,15 +258,21 @@ while (Path != CurrentPath) { LLVM_DEBUG(llvm::dbgs() << "Caching configuration for path " << Path << ".\n"); - CachedOptions[Path] = *Result; + if (!CachedOptions.count(Path)) + CachedOptions[Path] = *Result; Path = llvm::sys::path::parent_path(Path); } CachedOptions[Path] = *Result; RawOptions.push_back(*Result); - break; + if (!Result->first.InheritParentConfig || + !*Result->first.InheritParentConfig) + break; } } + // Reverse order of file configs because closer configs should have higher + // priority. + std::reverse(RawOptions.begin() + FirstFileConfig, RawOptions.end()); RawOptions.push_back(CommandLineOptions); return RawOptions; } diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/3/.clang-tidy b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/3/.clang-tidy new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/3/.clang-tidy @@ -0,0 +1,3 @@ +InheritParentConfig: true +Checks: 'from-child3' +HeaderFilterRegex: 'child3' diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp --- a/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp @@ -7,6 +7,9 @@ // RUN: clang-tidy -dump-config %S/Inputs/config-files/2/- -- | FileCheck %s -check-prefix=CHECK-CHILD2 // CHECK-CHILD2: Checks: {{.*}}from-parent // CHECK-CHILD2: HeaderFilterRegex: parent +// RUN: clang-tidy -dump-config %S/Inputs/config-files/3/- -- | FileCheck %s -check-prefix=CHECK-CHILD3 +// CHECK-CHILD3: Checks: {{.*}}from-parent,from-child3 +// CHECK-CHILD3: HeaderFilterRegex: child3 // RUN: clang-tidy -dump-config -checks='from-command-line' -header-filter='from command line' %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-COMMAND-LINE // CHECK-COMMAND-LINE: Checks: {{.*}}from-parent,from-command-line // CHECK-COMMAND-LINE: HeaderFilterRegex: from command line