diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -43,13 +43,14 @@ hasTemplateArgument(0, refersToType(type().bind("T")))); } -auto hasOptionalType() { return hasType(optionalClass()); } - -auto hasOptionalOrAliasType() { +auto optionalOrAliasType() { return hasUnqualifiedDesugaredType( recordType(hasDeclaration(optionalClass()))); } +/// Matches any of the spellings of the optional types and sugar, aliases, etc. +auto hasOptionalType() { return hasType(optionalOrAliasType()); } + auto isOptionalMemberCallWithName( llvm::StringRef MemberName, llvm::Optional Ignorable = llvm::None) { @@ -164,9 +165,8 @@ } auto isCallReturningOptional() { - return callExpr(callee(functionDecl( - returns(anyOf(hasOptionalOrAliasType(), - referenceType(pointee(hasOptionalOrAliasType()))))))); + return callExpr(callee(functionDecl(returns(anyOf( + optionalOrAliasType(), referenceType(pointee(optionalOrAliasType()))))))); } /// Creates a symbolic value for an `optional` value using `HasValueVal` as the @@ -485,8 +485,9 @@ return MatchSwitchBuilder() // Attach a symbolic "has_value" state to optional values that we see for // the first time. - .CaseOf(expr(anyOf(declRefExpr(), memberExpr()), hasOptionalType()), - initializeOptionalReference) + .CaseOf( + expr(anyOf(declRefExpr(), memberExpr()), hasOptionalType()), + initializeOptionalReference) // make_optional .CaseOf(isMakeOptionalCall(), transferMakeOptionalCall) diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp @@ -2214,6 +2214,23 @@ UnorderedElementsAre(Pair("check-4", "unsafe: input.cc:10:7"))); } +// Verifies that the model sees through aliases. +TEST_P(UncheckedOptionalAccessTest, WithAlias) { + ExpectLatticeChecksFor( + R"( + #include "unchecked_optional_access_test.h" + + template + using MyOptional = $ns::$optional; + + void target(MyOptional opt) { + opt.value(); + /*[[check]]*/ + } + )", + UnorderedElementsAre(Pair("check", "unsafe: input.cc:8:7"))); +} + // FIXME: Add support for: // - constructors (copy, move) // - assignment operators (default, copy, move)