[nullability] Handle class templates with default arguments
PiperOrigin-RevId: 543418334
diff --git a/nullability/test/templates.cc b/nullability/test/templates.cc
index 7890d42..8658626 100644
--- a/nullability/test/templates.cc
+++ b/nullability/test/templates.cc
@@ -1176,6 +1176,21 @@
)cc"));
}
+TEST(PointerNullabilityTest, ClassTemplateWithDefaultArgument) {
+ // Crash repro.
+ EXPECT_TRUE(checkDiagnostics(R"cc(
+ template <class T1, class T2 = T1>
+ struct S {
+ public:
+ void f(S<T2>);
+ };
+ void target() {
+ S<int* _Nullable> s;
+ s.f(s);
+ }
+ )cc"));
+}
+
} // namespace
} // namespace nullability
} // namespace tidy
diff --git a/nullability/type_nullability.cc b/nullability/type_nullability.cc
index 99df54b..caf312f 100644
--- a/nullability/type_nullability.cc
+++ b/nullability/type_nullability.cc
@@ -274,6 +274,16 @@
ignoreUnexpectedNullability();
Visit(CRD->getDeclContext());
for (auto TA : TST->template_arguments()) Visit(TA);
+ // `TST->template_arguments()` doesn't contain any default arguments.
+ // Retrieve these (though in unsugared form) from the
+ // `ClassTemplateSpecializationDecl`.
+ // TODO(b/281474380): Can we fetch or compute default arguments in sugared
+ // form?
+ if (auto* CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CRD)) {
+ for (unsigned i = TST->template_arguments().size();
+ i < CTSD->getTemplateArgs().size(); ++i)
+ Visit(CTSD->getTemplateArgs()[i]);
+ }
}
void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType* T) {
diff --git a/nullability/type_nullability_test.cc b/nullability/type_nullability_test.cc
index e8d760c..adf672d 100644
--- a/nullability/type_nullability_test.cc
+++ b/nullability/type_nullability_test.cc
@@ -357,6 +357,16 @@
ElementsAre(NullabilityKind::Unspecified));
}
+TEST_F(GetNullabilityAnnotationsFromTypeTest, ClassTemplateWithDefaultArg) {
+ Preamble = "template <typename T1, typename T2 = T1> class ClassTemplate {};";
+
+ // TODO(b/281474380): This should be [Nullable, Nullable], but we don't yet
+ // handle default arguments correctly.
+ EXPECT_THAT(
+ nullVec("ClassTemplate<int * _Nullable>"),
+ ElementsAre(NullabilityKind::Nullable, NullabilityKind::Unspecified));
+}
+
TEST_F(GetNullabilityAnnotationsFromTypeTest, TemplateArgsBehindAlias) {
Preamble = R"cpp(
template <class X>