- Add a HeaderFileExtensions check option in misc-definitions-in-headers, google-build-namespaces and google-global-names-in-headers.
Details
Diff Detail
Event Timeline
Public-facing documentation should also be updated to specify the new option for the various checkers.
clang-tidy/ClangTidy.h | ||
---|---|---|
55 | "in both options" -> "in either list" | |
57 | Any reason for Default to not be a StringRef (I assume this is always going to be a hard-coded string literal in callers)? At the very least, it should be a const std::string &. | |
clang-tidy/ClangTidyOptions.cpp | ||
269 | This code seems like it will fail if there are spaces in the extension list, like .h, .hxx instead of .h,.hxx. I think the list, as given by the end user, should be processed into a vector of sorts so that things can be normalized (entries without a period can be diagnosed, spaces removed, etc). | |
270 | clang-format the patch. | |
clang-tidy/ClangTidyOptions.h | ||
216 | endsWithHeaderFileExtension instead? However, given that uses of this all start with a SourceLocation, I wonder if that makes for a cleaner API: isLocInHeaderFile(SourceLocation, <Extensions>); Also, how does this work if I want to include an extension-less file as the header file "extension?" It would be plausible if the extensions were passed in as a list, but as it stands it doesn't seem possible without weird conventions like leaving a blank in the list (e.g., .h,,.hpp), which seems error-prone. Also, I'm not certain what I can pass in. The documentation should be updated to state whether these extensions are intended to include the ".". |
clang-tidy/ClangTidyOptions.h | ||
---|---|---|
216 |
Using SourceLocation only is not enough to retrieve the belonging file name (we need SourceManager too).
Yeah, for extensions-less header file, you can pass the string like .h,,.hpp, which is a bit of weird. Do you have a better idea here? Passing a string into header-file-extensions seems the most reasonable choice. |
Thank you for the patch! I have a few concerns though. See inline comments.
clang-tidy/ClangTidy.cpp | ||
---|---|---|
348 | There's no need to declare a vector: for (const string &s : {"a", "b", "c"}) .... Also, I don't think it makes sense to create a vector of two elements and run a loop over it instead of duplicating three lines of code. | |
clang-tidy/ClangTidy.h | ||
54 | We need to explicitly specify the order in which the options are considered: local, global, default. | |
clang-tidy/ClangTidyOptions.cpp | ||
269 | It's rather inefficient to split the string each time the function is called. If even we needed this function, we would better pass an ArrayRef<StringRef>. But even better, we can use llvm::StringSet and get rid of this function at all (we might need a helper function to parse a comma-separated list of extensions to a StringSet though). | |
clang-tidy/ClangTidyOptions.h | ||
216 | This function doesn't belong here. I'm also not sure we need this function at all. First, it's ineffective to split the string containing the list of extensions each time. Second, if we store a set of extensions, then we can just search for the actual file extension in this set. | |
clang-tidy/google/GlobalNamesInHeadersCheck.h | ||
23 | nit: s/There is one option:/The check supports these options:/ | |
24 | s/the file extensions that regard as header file/a comma-separated list of filename extensions of header files/ I don't think this list should include the period. It's better to just store extensions as returned by llvm::sys::path::extension(), so that it can be simply looked up in a set. Also, it's common to indent lists, so please insert two spaces at the beginning of this line and the next one. | |
33 | As mentioned earlier, this can be a set of strings (e.g. llvm::StringSet). | |
clang-tidy/misc/DefinitionsInHeadersCheck.cpp | ||
22 | s/useHeaderFileExtension/usesHeaderFileExtension/ | |
clang-tidy/tool/ClangTidyMain.cpp | ||
78 | We don't need a command-line flag for this. The regular way to configure clang-tidy is .clang-tidy files. However, if needed, check options can be configured from the command line via the -config= option. |
clang-tidy/ClangTidyOptions.h | ||
---|---|---|
216 | isLocInHeaderFile(SourceLocation, ...) is a nice idea, but we'd need to be more specific: either isExpansionLocInHeaderFile(SourceLoc, ...) or isSpellingLocInHeaderFile(SourceLoc, ...) (or both). |
clang-tidy/tool/ClangTidyMain.cpp | ||
---|---|---|
78 | From my understanding, it is a global option for header-file-extensions, right? If we remove this command-line flag, there is only local header-file-extensions option remained for particular checks. |
clang-tidy/tool/ClangTidyMain.cpp | ||
---|---|---|
78 | Both local and global options reside in CheckOptions and can be configured in the same way using either a .clang-tidy file or the -config= command-line option. The only difference between local and global options is that the name of the latter is not prefixed with the "CheckName.". Makes sense? |
clang-tidy/ClangTidyOptions.h | ||
---|---|---|
216 |
I thought those user configurations from the command line were in YAML or JSON format, those both have the notion of lists, don't they? I would imagine this would take a SmallVectorImpl<StringRef/std::string> for the list of extensions. | |
216 |
That's true, and I would think both are reasonable to add. I rather prefer that as an API instead of passing around file names as strings, personally. | |
clang-tidy/tool/ClangTidyMain.cpp | ||
78 |
Ah, thank you for that explanation. I learned something new today. ;-) |
clang-tidy/ClangTidyOptions.h | ||
---|---|---|
216 | User configurations are stored in YAML, however, CheckOptions is a map of strings to strings, so we can't use YAML lists to represent lists of extensions. |
clang-tidy/ClangTidyOptions.h | ||
---|---|---|
216 |
I find it to be more clever than intuitive. If it were not user-facing, I would be less concerned. I don't think users should have to read documentation to figure out the *syntax* of how to pass options if we can at all avoid it. ;-) Regardless, I would like to separate the two concepts -- there's the way we expose the option to the users, and there's our internal APIs that we call. I don't think the internal API has to take such an awkward thing directly just because the user-facing option has to be that way currently. |
clang-tidy/ClangTidyOptions.h | ||
---|---|---|
216 | This aligns with what I wrote in my first comment on this:
I still think the function doesn't belong here. And we also shouldn't split the string each time we call it. So I suggest adding these functions to clang-tidy/utils/: bool isExpansionLocInHeader(const? SourceManager &SM, SourceLocation Loc, const StringSet &HeaderFileExtensions); bool isSpellingLocInHeader(const? SourceManager &SM, SourceLocation Loc, const StringSet &HeaderFileExtensions); StringSet splitCommaSeparatedSet(StringRef S); // Or something similar. |
clang-tidy/utils/HeaderFileExtensionsUtils.cpp | ||
---|---|---|
48 ↗ | (On Diff #45006) | One thing we may want to reconsider for this function is using comma as a delimiter. We have another in-flight review which has to use semi-colons for a checker option list because commas are part of the syntax for a type description (think Foo<A, B>). It would be really nice to have one utility for parsing lists of information from checker options, and for that to use the same delimiter everywhere so that users aren't confused by using commas in some places and semi-colons in others. |
clang-tidy/ClangTidyOptions.cpp | ||
---|---|---|
269 | Now it's tolerant of whitespace around the commas. |
clang-tidy/google/GlobalNamesInHeadersCheck.h | ||
---|---|---|
25 | s/includ/include Is "." tolerated in the extension? It sounds like you can write: h,.hpp,hxx and it will work? Best to clarify the requirements (here and elsewhere). I don't have a strong opinion on whether the extension should include the full stop or not. | |
27 | What if you only want to match extensionless header files? | |
clang-tidy/google/UnnamedNamespaceInHeaderCheck.h | ||
24 | s/includ/include Same comment about use of ".". | |
clang-tidy/misc/DefinitionsInHeadersCheck.h | ||
36 | s/includ/include Also, same comments about the full stop. |
Mostly looks good, except I do still have the question about list delimiters that I'd like to hear some thoughts on. My primary concern is that I hope to avoid having different separators for different lists, and I wonder whether we want a common "parse a list of stuff" interface for the options that then gets used by functions like parseHeaderFileExtensions() to do sanitization of the list as-needed.
clang-tidy/utils/HeaderFileExtensionsUtils.cpp | ||
---|---|---|
49 ↗ | (On Diff #45349) | I'm +1 on keeping the consistence of list option. I also check the option in clang-tidy checks, seems that this is the first time to introduce list option into clang-tidy. So ; is fine to me. |
Sorry for the delay. A few more comments.
clang-tidy/google/GlobalNamesInHeadersCheck.cpp | ||
---|---|---|
30 | That's not the best way to report errors, especially, when clang-tidy is used as a library. There are multiple possibilities, e.g. add a callback to ClangTidyContext (or a method to ClangTidyCheck) to report a problem with configuration, or move to two-stage initialization of checks, or something similar. No need to change this now, but please add a FIXME to find a more suitable way to handle invalid configuration options. | |
56 | No need for the parentheses around Result.SourceManager. | |
clang-tidy/utils/HeaderFileExtensionsUtils.cpp | ||
50 ↗ | (On Diff #45852) |
Comma is used as a delimiter in two more checks' options: clang-tidy/modernize/UseNullptrCheck.cpp and clang-tidy/misc/AssertSideEffectCheck.cpp. It's also used on the command line for the -checks and -warnings-as-errors options. I'm not sure what to do here, if we want consistency. For now, I'd rather switch back to comma and maybe provide a more generic facility to parse lists from clang-tidy options, which could also handle both separators in a smart way (e.g. when the list contains semicolons, use only them - this will allow listing entries like "A<B,T>", otherwise use comma; maybe also support some other separator, say | for cases when we need to list entries containing semicolons). |
clang-tidy/utils/HeaderFileExtensionsUtils.h | ||
23 ↗ | (On Diff #45852) | That's an unnecessary long and too specific namespace name. I'd go for just utils, at least for now. |
33 ↗ | (On Diff #45852) | Don't add unused functions. When someone needs them, they can add them. |
Looks good with a couple of comments. Thanks for working on this!
clang-tidy/utils/HeaderFileExtensionsUtils.cpp | ||
---|---|---|
45 ↗ | (On Diff #46897) | No need for llvm:: here. |
46 ↗ | (On Diff #46897) | Actually, this could be changed to a more generic parseStringSetOption or something similar. Let's do this in a follow up. But for now we need to change the output parameter type to llvm::SmallSetImpl<StringRef> to avoid hardcoding the small size template argument. The typedef is then not useful anymore. |
clang-tidy/utils/HeaderFileExtensionsUtils.h | ||
34 ↗ | (On Diff #46897) | Ah, missed this somehow. Then it's fine. I'm not sure though, whether PresumedLocation is the right thing in that check, but we can figure this out later. |
clang-tidy/misc/DefinitionsInHeadersCheck.cpp | ||
---|---|---|
44 | It's common to use just FIXME:, without the reference to the author. |
clang-tidy/utils/HeaderFileExtensionsUtils.cpp | ||
---|---|---|
46 ↗ | (On Diff #46897) |
I can't find llvm::SmallSetImpl or any similar Set without size template argument. |
clang-tidy/utils/HeaderFileExtensionsUtils.cpp | ||
---|---|---|
46 ↗ | (On Diff #46897) | Hm, indeed SmallSet has no base class unlike SmallVector, for example. Ok, then seems good for now. |
A couple of post-commit comments.
clang-tools-extra/trunk/clang-tidy/google/GlobalNamesInHeadersCheck.h | ||
---|---|---|
24 ↗ | (On Diff #47007) | BTW, this belongs to the user-facing doc, so please move this to the .rst file. Same for other checks. |
clang-tools-extra/trunk/clang-tidy/utils/HeaderFileExtensionsUtils.cpp | ||
53 ↗ | (On Diff #47007) | BTW, you should be able to use a range-based for loop. |
We need to explicitly specify the order in which the options are considered: local, global, default.