[clang-tools-extra] e8f4a01 - [clangd] Fix a hover crash on templated spaceship operator.
Adam Czachorowski via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 26 08:31:22 PDT 2021
Author: Adam Czachorowski
Date: 2021-10-26T17:28:40+02:00
New Revision: e8f4a01189143854f30e2bb622baa729a42f152d
URL: https://github.com/llvm/llvm-project/commit/e8f4a01189143854f30e2bb622baa729a42f152d
DIFF: https://github.com/llvm/llvm-project/commit/e8f4a01189143854f30e2bb622baa729a42f152d.diff
LOG: [clangd] Fix a hover crash on templated spaceship operator.
We make assumption that:
getDeclForComment(getDeclForComment(X)) == getDeclForComment(X)
but this is not true if you have a template
instantionation of a template instantiation, which is the case when, for
example, you have a <=> operator in a templated class.
This fix makes getDeclForComment() call itself recursively to ensure
this property is always true.
Fixes https://github.com/clangd/clangd/issues/901
Differential Revision: https://reviews.llvm.org/D112527
Added:
Modified:
clang-tools-extra/clangd/Hover.cpp
clang-tools-extra/clangd/unittests/HoverTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 8ef7d20c1d53..4285b3595059 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -262,24 +262,30 @@ const FunctionDecl *getUnderlyingFunction(const Decl *D) {
// Returns the decl that should be used for querying comments, either from index
// or AST.
const NamedDecl *getDeclForComment(const NamedDecl *D) {
+ const NamedDecl *DeclForComment = D;
if (const auto *TSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) {
// Template may not be instantiated e.g. if the type didn't need to be
// complete; fallback to primary template.
if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
- return TSD->getSpecializedTemplate();
- if (const auto *TIP = TSD->getTemplateInstantiationPattern())
- return TIP;
- }
- if (const auto *TSD = llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ DeclForComment = TSD->getSpecializedTemplate();
+ else if (const auto *TIP = TSD->getTemplateInstantiationPattern())
+ DeclForComment = TIP;
+ } else if (const auto *TSD =
+ llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) {
if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
- return TSD->getSpecializedTemplate();
- if (const auto *TIP = TSD->getTemplateInstantiationPattern())
- return TIP;
- }
- if (const auto *FD = D->getAsFunction())
+ DeclForComment = TSD->getSpecializedTemplate();
+ else if (const auto *TIP = TSD->getTemplateInstantiationPattern())
+ DeclForComment = TIP;
+ } else if (const auto *FD = D->getAsFunction())
if (const auto *TIP = FD->getTemplateInstantiationPattern())
- return TIP;
- return D;
+ DeclForComment = TIP;
+ // Ensure that getDeclForComment(getDeclForComment(X)) = getDeclForComment(X).
+ // This is usually not needed, but in strange cases of comparision operators
+ // being instantiated from spasceship operater, which itself is a template
+ // instantiation the recursrive call is necessary.
+ if (D != DeclForComment)
+ DeclForComment = getDeclForComment(DeclForComment);
+ return DeclForComment;
}
// Look up information about D from the index, and add it to Hover.
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 6395da91463a..2e33ce4c5d10 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2934,6 +2934,35 @@ Value = val
def)pt";
EXPECT_EQ(HI.present().asPlainText(), ExpectedPlaintext);
}
+
+TEST(Hover, SpaceshipTemplateNoCrash) {
+ Annotations T(R"cpp(
+ namespace std {
+ struct strong_ordering {
+ int n;
+ constexpr operator int() const { return n; }
+ static const strong_ordering equal, greater, less;
+ };
+ constexpr strong_ordering strong_ordering::equal = {0};
+ constexpr strong_ordering strong_ordering::greater = {1};
+ constexpr strong_ordering strong_ordering::less = {-1};
+ }
+
+ template <typename T>
+ struct S {
+ // Foo bar baz
+ friend auto operator<=>(S, S) = default;
+ };
+ static_assert(S<void>() =^= S<void>());
+ )cpp");
+
+ TestTU TU = TestTU::withCode(T.code());
+ TU.ExtraArgs.push_back("-std=c++20");
+ auto AST = TU.build();
+ auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
+ EXPECT_EQ(HI->Documentation, "Foo bar baz");
+}
+
} // namespace
} // namespace clangd
} // namespace clang
More information about the cfe-commits
mailing list