ken-matsui added a comment. Thank you so much for your clear review!
================ Comment at: clang/include/clang/Basic/DiagnosticGroups.td:1023-1024 +// Typoed directive warnings +def TypoedDirective : DiagGroup<"typoed-directive">; + ---------------- aaron.ballman wrote: > We don't typically use "typo" in the user-facing part of diagnostics and this > group doesn't seem likely to be reused, so I would remove it (another comment > on this elsewhere). Ah, I see. Thank you! ================ Comment at: clang/include/clang/Basic/DiagnosticLexKinds.td:362-365 +def warn_pp_typo_directive : Warning< + "'#%0' directive not found, did you mean '#%1'?">, + InGroup<TypoedDirective>; ---------------- aaron.ballman wrote: > Rather than adding a warning over the top of an existing error, I think we > should modify `err_pp_invalid_directive` to have an optional "did you mean?" > when we find a plausible typo to correct. > > However, we do not issue that diagnostic when it's inside of a skipped > conditional block, and that's what the crux of > https://github.com/llvm/llvm-project/issues/51598 is about. As @rsmith > pointed out in that issue (and I agree), compilers are free to support custom > directives and those will validly appear inside of a conditional block that > is skipped. We need to be careful not to diagnose those kinds of situations > as an error. However, we still want to diagnose when the unknown directive is > "sufficiently close" to another one which can control the conditional chain. > e.g., > ``` > #fi FOO // error unknown directive, did you mean #if? > #endfi // error unknown directive, did you mean #endif? > > #if FOO > #esle // diag: unknown directive, did you mean #else? > #elfi // diag: unknown directive, did you mean #elif? > #elfidef // diag: unknown directive, did you mean #elifdef > #elinfdef // diag: unknown directive, did you mean #elifndef > > #frobble // No diagnostic, not close enough to a conditional directive to > warrant diagnosing > #eerp // No diagnostic, not close enough to a conditional directive to > warrant diagnosing > > #endif > ``` > Today, if `FOO` is defined to a nonzero value, you'll get diagnostics for all > of those, but if `FOO` is not defined or is defined to 0, then there's no > diagnostics. I think we want to consider directives that are *very likely* to > be a typo (edit distance of 1, maybe 2?) for a conditional directive as a > special case. > > Currently, we only diagnose unknown directives as an error. I think for these > special cased conditional directive diagnostics, we'll want to use a warning > rather than an error in this circumstance (just in case it turns out to be a > valid directive in a skipped conditional block). If we do go that route and > make it a warning, I think the warning group should be `-Wunknown-directives` > to mirror `-Wunknown-pragmas`, `-Wunknown-attributes`, etc and it should be > defined to have the same text as the error case. e.g., > ``` > def err_pp_invalid_directive : Error< > "invalid preprocessing directive%select{|; did you mean '#%1'?}0" > >; > def warn_pp_invalid_directive : Warning< > err_pp_invalid_directive.Text>, InGroup<DiagGroup<"unknown-directives">>; > ``` > WDYT? > > (These were my thoughts before seeing the rest of the patch. After reading > the patch, it looks like we have pretty similar ideas here, which is great, > but leaving the comment anyway in case you have further opinions.) > Currently, we only diagnose unknown directives as an error. I think for these > special cased conditional directive diagnostics, we'll want to use a warning > rather than an error in this circumstance (just in case it turns out to be a > valid directive in a skipped conditional block). If we do go that route and > make it a warning, I think the warning group should be `-Wunknown-directives` > to mirror `-Wunknown-pragmas`, `-Wunknown-attributes`, etc and it should be > defined to have the same text as the error case. e.g., > ``` > def err_pp_invalid_directive : Error< > "invalid preprocessing directive%select{|; did you mean '#%1'?}0" > >; > def warn_pp_invalid_directive : Warning< > err_pp_invalid_directive.Text>, InGroup<DiagGroup<"unknown-directives">>; > ``` > WDYT? > > (These were my thoughts before seeing the rest of the patch. After reading > the patch, it looks like we have pretty similar ideas here, which is great, > but leaving the comment anyway in case you have further opinions.) For now, I totally agree with deriving a new warning from `err_pp_invalid_directive`. However, for future scalability, I think it would be great if we could split those diagnostics into Error & Warning and Help, for example. Rustc does split the diagnostics like the following, and I think this is quite clear. So, a bit apart from this patch, I speculate creating a diagnostic system that can split them would bring Clang diagnostics much more readable. https://github.com/rust-lang/rust/blob/598d89bf142823b5d84e2eb0f0f9e418ee966a4b/src/test/ui/suggestions/suggest-trait-items.stderr ================ Comment at: clang/include/clang/Tooling/LevDistance.h:1 +//===--- LevDistance.h ------------------------------------------*- C++ -*-===// +// ---------------- aaron.ballman wrote: > You shouldn't need this file or the implementation file -- we have this > functionality already in: > https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/edit_distance.h > and > https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/StringRef.h#L240. I totally missed the implementations! Sorry. But where should I put both `findSimilarStr` & `findSimilarStr`? It seems that their same implementations aren't there. ================ Comment at: clang/lib/Lex/PPDirectives.cpp:441-449 + const SourceLocation &endLoc) { + const std::array<std::string, 8> candidates{ + "if", "ifdef", "ifndef", "elif", "elifdef", "elifndef", "else", "endif"}; + + if (const auto sugg = + tooling::levdistance::findSimilarStr(candidates, Directive)) { + CharSourceRange DirectiveRange = ---------------- aaron.ballman wrote: > Mostly just cleaning up for coding conventions, but also, no need to use a > `std::array` and we typically don't use local top-level `const` qualification. Thank you! Just wondering, but is there any reason not to use the `const` qualifier? ================ Comment at: clang/test/OpenMP/predefined_macro.c:7 // RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -verify -o - %s -// expected-no-diagnostics +// expected-warning@+5 {{'#elsif' directive not found, did you mean '#elif'?}} #ifdef FOPENMP ---------------- aaron.ballman wrote: > ken-matsui wrote: > > I am not sure if this typo was intended. > > > > When I renamed `elsif` to `elif`, `#error "_OPENMP has incorrect value"` on > > line `13` was evaluated. > > > > Therefore, if this typo was intended, just suppressing the warning with > > `expected-warning` would be better. However, if this typo was NOT intended, > > I think I should make `_OPENMP` equal to `201107`. It is also possible that > > this test was mistakenly written. > I tracked down the root cause here and fixed the bug in > 50b51b1860acbfb775d5e2eee3310e25c635d667, so when you rebase on main you > won't have to deal with this any longer. Good catch! Thank you for fixing the bug! I could confirm the bug was fixed upstream. ================ Comment at: clang/test/Preprocessor/suggest-typoed-directive.c:10 +// expected-warning@+11 {{'#elfidef' directive not found, did you mean '#elifdef'?}} +// expected-warning@+11 {{'#elfindef' directive not found, did you mean '#elifdef'?}} +// expected-warning@+11 {{'#elsi' directive not found, did you mean '#else'?}} ---------------- aaron.ballman wrote: > It's interesting that this one suggested `#elifdef` instead of `#elifndef` -- > is there anything that can be done for that? > > Also, one somewhat interesting question is whether we want to recommend > `#elifdef` and `#elifndef` outside of C2x/C++2b mode. Those directives only > exist in the latest language standard, but Clang supports them as a > conforming extension in all language modes. Given that this diagnostic is > about typos, I think I'm okay suggesting the directives even in older > language modes. That's as likely to be a correct suggestion as not, IMO. > It's interesting that this one suggested `#elifdef` instead of `#elifndef` -- > is there anything that can be done for that? I found I have to use `std::min_element` instead of `std::max_element` because we are finding the nearest (most minimum distance) string. Meanwhile, `#elfindef` has 2 distance with both `#elifdef` and `#elifndef`. After replacing `std::max_element` with `std::min_element`, I could suggest `#elifndef` from `#elfinndef`. > Also, one somewhat interesting question is whether we want to recommend > `#elifdef` and `#elifndef` outside of C2x/C++2b mode. Those directives only > exist in the latest language standard, but Clang supports them as a > conforming extension in all language modes. Given that this diagnostic is > about typos, I think I'm okay suggesting the directives even in older > language modes. That's as likely to be a correct suggestion as not, IMO. I agree with you because Clang implements those directives, and the suggested code will also be compilable. I personally think only not compilable suggestions should be avoided. (Or, we might place additional info for outside of C2x/C++2b mode like `this is a C2x/C++2b feature but compilable on Clang`?) --- According to the algorithm of `std::min_element`, we only get an iterator of the first element even if there is another element that has the same distance. So, `#elfindef` only suggests `#elifdef` in accordance with the order of `Candidates`, and I don't think it is beautiful to depend on the order of candidates. I would say that we can suggest all the same distance like the following, but I'm not sure this is preferable: ``` #elfindef // diag: unknown directive, did you mean #elifdef or #elifndef? ``` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D124726/new/ https://reviews.llvm.org/D124726 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits