[PATCH] D56903: [clangd] Suggest adding missing includes for incomplete type diagnostics.

Sam McCall via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 25 07:40:08 PST 2019


sammccall accepted this revision.
sammccall added a comment.
This revision is now accepted and ready to land.

Just a bunch of nits, up to you to work out how/whether to address.

One substantive issue around classes defined outside headers - will chat offline.



================
Comment at: clangd/ClangdServer.h:118
+
+    bool EnableIncludeFixer = false;
   };
----------------
Can we call this option `SuggestMissingIncludes` or so? include-fixer is the name of a separate tool.


================
Comment at: clangd/ClangdUnit.cpp:295
 
+  llvm::Optional<IncludeFixer> FixIncludes;
+  auto BuildDir = VFS->getCurrentWorkingDirectory();
----------------
sammccall wrote:
> Probably worth a two-line comment explaining at a high level what this is doing.
> Somewhat redundant with `IncludeFixer.h` but probably worth it anyway since this containing function is a complicated mess.
nit: can you hoist this above the line declaring FixIncludes?
That way (I think) it reads more naturally as "this is what the following block of code does" in a big method, doesn't fold away with the if, etc


================
Comment at: clangd/ClangdUnit.cpp:305
+    }
+    FixIncludes.emplace(MainInput.getFile(), std::move(Inserter), *Index);
+    ASTDiags.contributeFixes([&FixIncludes](DiagnosticsEngine::Level DiagLevl,
----------------
nit: I'm not sure I agree with the IncludeFixer class taking ownership of the include inserter.
It reads it but never writes to it, so full ownership isn't *needed*. And if we had other features that wanted to compute include insertions, we'd want them to share an inserter.


================
Comment at: clangd/Compiler.h:49
+  // Used to recover from diagnostics (e.g. find missing includes for symbol).
+  llvm::Optional<const SymbolIndex *> Index;
+  ParseOptions Opts;
----------------
isn't an optional pointer just a pointer?


================
Comment at: clangd/IncludeFixer.cpp:39
+                                   const clang::Diagnostic &Info) const {
+  if (IndexRequestCount >= 5)
+    return {}; // Avoid querying index too many times in a single parse.
----------------
consider moving this 5 to a constructor param, so this file can be entirely mechanism and the policy is spelled out at the construction site.
(No need to actually make it configurable, I think)


================
Comment at: clangd/IncludeFixer.cpp:41
+    return {}; // Avoid querying index too many times in a single parse.
+  if (isIncompleteTypeDiag(Info.getID())) {
+    // Incomplete type diagnostics should have a QualType argument for the
----------------
(You could also just write this as just a switch on Info.getID(), I'd find that a little direct/easier to read, up to you)


================
Comment at: clangd/IncludeFixer.cpp:61
+    return {};
+  std::string IncompleteType = printQualifiedName(*TD);
+  if (IncompleteType.empty()) {
----------------
TypeName?


================
Comment at: clangd/IncludeFixer.cpp:63
+  if (IncompleteType.empty()) {
+    vlog("No incomplete type name is found in diagnostic. Ignore.");
+    return {};
----------------
this seems an odd thing to check and way to phrase - there *was* a type in the message, but its name happens to be empty. Am I missing something? (I'd suggest just removing this)


================
Comment at: clangd/IncludeFixer.cpp:80
+  Index.lookup(Req, [&](const Symbol &Sym) {
+    // FIXME: support multiple matched symbols.
+    if (Matched || (Sym.Scope + Sym.Name).str() != IncompleteType)
----------------
fixme is obsolete


================
Comment at: clangd/IncludeFixer.cpp:81
+    // FIXME: support multiple matched symbols.
+    if (Matched || (Sym.Scope + Sym.Name).str() != IncompleteType)
+      return;
----------------
no need to check name


================
Comment at: clangd/IncludeFixer.cpp:86
+
+  if (!Matched || Matched->IncludeHeaders.empty())
+    return {};
----------------
There's a case I'm worried about:

Foo.h declares `class X;`, Foo.cpp defines `class X{}`.
Now Bar.cpp tries to do `sizeof(X)`, so we get an incomplete type diagnostic.
 - suggesting `#include Foo.cpp` is bad - can't include impl file
 - suggesting `#include Foo.h` is also bad - doesn't help
 - providing no suggestion is correct.

I'm not sure the index really has enough structured information to detect this case, but we could check e.g. that definition header == canonical declaration header? Or that basename(IncludeHeaders) == basename(definition header)?

If possible, can you add a test for this case?


================
Comment at: clangd/IncludeFixer.h:39
+  /// Attempts to recover diagnostic caused by an incomplete type \p T.
+  std::vector<Fix> fixInCompleteType(const Type &T) const;
+
----------------
sammccall wrote:
> nit: incomplete is one word
not done - method is still "fixInCompleteType"


================
Comment at: clangd/tool/ClangdMain.cpp:210
 
+static llvm::cl::opt<bool> EnableIncludeFixer(
+    "include-fixer",
----------------
similarly, I'd call this -suggest-missing-includes or just -suggest-includes


================
Comment at: clangd/tool/ClangdMain.cpp:214
+                   "includes using index."),
+    llvm::cl::init(false), llvm::cl::Hidden);
+
----------------
why hidden?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D56903/new/

https://reviews.llvm.org/D56903





More information about the cfe-commits mailing list