[PATCH] D144976: [clangd] Add provider info on symbol hover.
Haojian Wu via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 2 01:33:26 PST 2023
hokein added a comment.
Thanks, left a few comments on the implementation.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1091
+// FIXME(bakalova): Remove after merging https://reviews.llvm.org/D143496
+std::vector<include_cleaner::SymbolReference>
----------------
I'm not sure how we can do it. https://reviews.llvm.org/D143496 doesn't expose `collectMacroReferences` function, so we still duplicate this hacky implementations in two places, which is probably fine at the moment.
I think this will be fixed when we unify them with clangd's `CollectMainFileMacros`.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1093
+std::vector<include_cleaner::SymbolReference>
+collectMacroReferences(ParsedAST &AST) {
+ const auto &SM = AST.getSourceManager();
----------------
On a second thought, I think we might not really need it. We handle the macro vs non-macro cases separately, and we only care about the symbol reference under the cursor.
so we can simply the implementation:
1) For macro case, we already have the located macro and Tok in the call site (on line1231), we can just construct a single `include_cleaner::SymbolReference` from them, and pass a single-element `Macros` and empty `ASTRoots` to the `walkUsed` API.
2) For non-macro case, we can just pass an empty macro references to `walkUsed` as we already know the symbol under the hover is not a macro.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1123
+ if (!Ref.RefLocation.isFileID() ||
+ !SM.isWrittenInMainFile(SM.getSpellingLoc(Ref.RefLocation)))
+ // Ignore locations within macro expansions or not in the main file
----------------
no need to do the isWrittenInMainFile check in the callback, the walkUsed implementation already does it.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1128
+ if (Ref.RT != include_cleaner::RefType::Explicit)
+ // Ignore non-explicit references (e.g. variable names).
+ return;
----------------
I don't get it, why variable names are non-explicit references?
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1140
+ // Check that the user is hovering over the current symbol reference.
+ if (CurLoc < Ref.RefLocation || CurLoc > RefEndLocation) {
+ return;
----------------
We're using the location as a heuristic to join the symbol (Decl) from two difference sources (clangd's hover impl, and include-cleaner lib impl)
This heuristics works most of time, but it will fail in the case where the symbol under the hover is a `UsingDecl`
```
// absl_string_view.h
namespace absl {
using std::string_view;
}
// main.cpp
#includle "absl_string_view.h"
absl::str^ing_view abc; // hover on string_view
```
- clangd's hover uses the underlying decl (std::string_view), see the `pickDeclToUse` function for details;
- include-cleaner lib reports the using decl (asbl::string_view);
As a result, we will show the #include of the using decl for the underlying decl in the hover card.
To solve the issue, I think we need to check the equality of Decl from hover and Decl from `SymbolReference` (comparing both `getCanonicalDecl` should be enough).
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1153
+ SM.getFileEntryForID(SM.getMainFileID()) ==
+ Provider.physical()) {
+ // Do not report main file as provider.
----------------
We probably don't need to handle this main-file case specially, in practice, main-file is hardly included in the MainFileIncludes, so the following logic will filter the main-file as well.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1163
+ case include_cleaner::Header::Physical:
+ if (Provider.physical()->tryGetRealPathName() == Inc.Resolved)
+ DirectlyIncludedProviders.push_back(WrittenRef.str());
----------------
checking the spelled string can cause subtle behavior & bugs. A robust way is to use the `include_cleaner::Includes.match API` to determine a header is used or not (this is similar to what you did in https://reviews.llvm.org/D143496, we need to expose the transformation function `convertIncludes`)
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1172
+ if (Provider.verbatim() == Inc.Written)
+ DirectlyIncludedProviders.push_back(WrittenRef.str());
+ }
----------------
nit: I'd suggest adding a `break` even though it is the last case.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1181
+ HI.ProviderInfo = std::optional<std::vector<std::string>>{
+ std::move(DirectlyIncludedProviders)};
+ });
----------------
I wonder whether we need to deduplicate the `DirectlyIncludedProviders`, reading the code, it might be possible that we add duplicated headers, but in practice, we should only have a single Ref reported, so the deduplication is probably not needed.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1232
HI = getHoverContents(*M, Tok, AST);
+ if (HI)
+ maybeAddSymbolProviders(AST, *HI, *CurLoc);
----------------
nit: no need to check `HI`, it is always non-null as it is set by the above line.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1268
// Look for a close enclosing expression to show the value of.
- if (!HI->Value)
+ if (HI && !HI->Value)
HI->Value = printExprValue(N, AST.getASTContext());
----------------
any reason add a null check here, the HI should always be non-null becase we have set it on Line1263.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1335
+ if (ProviderInfo) {
+ Output.addRuler();
----------------
Is the code position intended? It looks like we're inserting the `Provided by XXX` text in the middle of the function return type and the function parameters, which seems weird to me. I think the function return type and parameters should group together.
Depending on the final UI, I think moving it before the `ReturnType` (right after the header) seems better than the current one.
================
Comment at: clang-tools-extra/clangd/Hover.cpp:1340
+ P.appendSpace();
+ for (unsigned I = 0; I < ProviderInfo->size() - 1; I++) {
+ P.appendCode((*ProviderInfo)[I]);
----------------
just use `llvm::join(*ProviderInfo, ", ");`
================
Comment at: clang-tools-extra/clangd/Hover.h:71
+ /// Headers providing the symbol (directly included in the main file).
+ std::optional<std::vector<std::string>> ProviderInfo;
std::optional<Range> SymRange;
----------------
I think we can get rid of the `std::optional` we can distinguish by checking the `ProviderInfo.empty()`.
Since we have 1 header for most cases, let use `llvm::SmallVector`.
We can store the `Inclusion*` as the container element, and convert to string during the `present()` call.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D144976/new/
https://reviews.llvm.org/D144976
More information about the cfe-commits
mailing list