Details
Diff Detail
- Repository
- rCTE Clang Tools Extra
- Build Status
Buildable 30619 Build 30618: arc lint + arc unit
Event Timeline
I'll look more closely into the details, but just a high-level question now: why would we want to make this optional and not simply surface these extra diagnostics?
The optional part is rather limiting number of diagnostics that is going to be surfaced. So if you have thousands of errors inside preamble only first 100 of them will appear inside main file by default.
But looking at it again, currently there is no way for user to say "do not limit number of diagnostics" :D They can only change this limit to different values.
Let's pick a number and hard-code it. We'll get consistent behavior in all clients of clangd, I can hardly think of any existing client that would want to surface everything to the user.
FWIW, 100 seem too much to my taste, since we're only showing errors. Would 10 be a better limit?
clangd/ClangdUnit.cpp | ||
---|---|---|
256 ↗ | (On Diff #191265) | We should find a way to point into an exact include directive (source locations have this information). |
406 ↗ | (On Diff #191265) | Could we limit per-include-directive instead? |
438 ↗ | (On Diff #191265) | We should provide the include stack, similar to how compiler does it. |
- Make limit a hardcoded value rather then a command line argument
- Limit diags per include directive
Thanks for changes. A few more comments.
clangd/ClangdUnit.cpp | ||
---|---|---|
259 ↗ | (On Diff #191465) | Could we binary-search in a sorted vector<Inclusion> with a custom comparator instead? |
411 ↗ | (On Diff #191465) | The function name suggests it does not have side-effects. |
clangd/Diagnostics.cpp | ||
419 | We can still drop diagnostics at some point, right? | |
465 | NIT: could we reuse the function from clang that does the same thing? The code here is pretty simple, though, so writing it here is fine. Just wanted to make sure we considered this option and found it's easier to redo this work ourselves. | |
clangd/Diagnostics.h | ||
88 | Could we avoid changing this interface? If that means intermediate structures stored in our consumer, so be it, it's a private implementation detail. Diag is a public interface, so keeping it simpler is valuable. | |
unittests/clangd/DiagnosticsTests.cpp | ||
761 | Could we add a test for reaching the limit? In file included from a.h:20:1: error: unresolved identifier 'foo'. And 10 more diagnostics... | |
788 | NIT: maybe use raw string literals to keep the message a one-liner? |
- Address comments
clangd/Diagnostics.cpp | ||
---|---|---|
465 | there is TextDiagnostic which prints the desired output expect the fact that it also prints the first line saying the header was included in main file. Therefore, I didn't make use of it since we decided that was not very useful for our use case. And it requires inheriting from DiagnosticRenderer which was requiring too much boiler plate code just to get this functionality so instead I've chosen doing it like this. Can fallback to TextDiagnostic if you believe showing Included in mainfile.cc:x:y: at the beginning of the diagnostic won't be annoying. | |
unittests/clangd/DiagnosticsTests.cpp | ||
761 | There is already one, see LimitDiagsOutsideMainFile |
clangd/ClangdUnit.cpp | ||
---|---|---|
405 ↗ | (On Diff #191831) | The name suggests we filter all diagnostics based on this helper. E.g. IsErrorOrFatal or IsImporantHeaderDiagnostic... |
408 ↗ | (On Diff #191831) | NIT: simplify to return D.Severity == DiagnosticsEngine::Level::Error || D.Severity == DiagnosticsEngine::Level::Fatal |
414 ↗ | (On Diff #191831) | NIT: rename to AddDiagnosticFromInclude or something similar, but more specific than the current name |
425 ↗ | (On Diff #191831) | Why not merge the ShouldSurfaceDiag and TryAddDiag into a single function and handle all the complexities there? else AddDiagnosticFromInclude(D) |
434 ↗ | (On Diff #191831) | Can we do this in StoreDiags::flushLastDiag? |
445 ↗ | (On Diff #191831) | This extra complexity does not seem to be worth it after all. Still think it's valuable, but the patch is complicated enough as it is, keeping it simpler seems to be more important at this point. |
clangd/Diagnostics.cpp | ||
440 | That's a lot of code, could we extract this into a separate function? | |
441 | Why use getPresumedLoc? Making clangd sensitive to pp directives that rename file or change line numbers does not make any sense. Could you also add tests for that? | |
465 | LG, it's not too hard to reconstruct the same output. We should eventually add the include stack into related information too. With that in mind, we should probably add the include stack as a new field to the struct we use for diagnostics. |
clangd/ClangdUnit.cpp | ||
---|---|---|
251 ↗ | (On Diff #194528) | NIT: use llvm::lower_bound |
252 ↗ | (On Diff #194528) | NIT: lower_bound also works when you work on a different type, no need for the temporary variable. lower_bound(MainFileIncludes…, [](const Inclusion &L, const Position &Pos) { return L.start.line < Pos.line; }) (the order of lamda parameters might need to be reversed, I always forget what's the correct one) |
255 ↗ | (On Diff #194528) | NIT: add a sanity check that the include was actually there: assert(Res->R == Pos) |
clangd/Diagnostics.cpp | ||
55 | reduce nesting by inverting the condition: if (IncludeStack.empty()) return; // rest of the code | |
216 | Could we get the message first and the include stack later? | |
477 | Could you inline ShouldAddDiag into its single callsite? | |
clangd/Diagnostics.h | ||
88 | Could you store pair</*Filename*/string, Position> instead? | |
131 | NIT: use tripple slash comments | |
132 | NIT: the name makes me believe this does a different thing. Maybe mention "include" in the name to make it less confusing? Another NIT: we don't need a map anymore: DenseSet<int> should be enough | |
unittests/clangd/DiagnosticsTests.cpp | ||
57 | NIT: maybe simplify to std::equal(IncludeStack.begin(), IncludeStack.end(), arg.IncludeStack.begin()) | |
621 | We were discussing adding the extra files to TestTU instead. |
- Address comments
unittests/clangd/DiagnosticsTests.cpp | ||
---|---|---|
621 | Yes, my LRU cache evicted the discussion :D |
clangd/Diagnostics.cpp | ||
---|---|---|
78 | Could we avoid introducing a function that breaks the invariant of a type? | |
225 | WDYT about changing this to a shorter form? include stack: ./project/foo.h:312 /usr/include/vector:344 Note that it does not mention column numbers as they aren't useful and is shorter. | |
unittests/clangd/DiagnosticsTests.cpp | ||
739 | So the last location in the include stack is actually the original location of an error. | |
unittests/clangd/TestTU.h | ||
51 | Maybe use relative paths? | |
52 | Why not StringMap</*Content*/std::string>? |
This looks nice and minimal, thanks!
Happy to LGTM this, unless @sammccall want to take another look (e.g. to account for related information patch)
Nice! Just readability/wording nits
clangd/Diagnostics.cpp | ||
---|---|---|
152 | Clang tends to use a phrase ending in "here" for such notes. | |
152 | message should not be capitalized (capitalization will be added later if needed) | |
156 | Include is not a noun. "included file"? | |
156 | "Error" is the severity, which appears elsewhere in LSP. (Other messages do not include it) | |
156 | message should not be capitalized | |
157 | why are we including the filename here? it obscures the error message, and will be available via the note. | |
477 | Does this improve readability over (inline) D.Severity >= DiagnosticsEngine::Error? | |
clangd/Diagnostics.h | ||
131 | nit: "containing an error" (and variable name) IncludeLinesWithErrors might be a clearer name |
Could we avoid changing this interface?
We have enough information to fill the corresponding range and message when collecting diagnostics inside our implementation of clang's DiagnosticConsumer, there's really no point in carrying this information in this struct.
If that means intermediate structures stored in our consumer, so be it, it's a private implementation detail. Diag is a public interface, so keeping it simpler is valuable.