blob: 5b5ba1a10f169fdaa9ad0471e04be69c2252069c [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "nullability/inference/inferable.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/LLVM.h"
#include "clang/Testing/TestAST.h"
#include "llvm/ADT/StringRef.h"
#include "third_party/llvm/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h"
namespace clang::tidy::nullability {
namespace {
template <class T = NamedDecl>
const T &lookup(llvm::StringRef Name, const DeclContext &DC) {
auto L = DC.lookup(&DC.getParentASTContext().Idents.get(Name));
EXPECT_TRUE(L.isSingleResult()) << Name;
auto *Result = L.find_first<T>();
EXPECT_NE(Result, nullptr) << Name;
return *Result;
}
TEST(InferableTest, IsInferenceTarget) {
TestAST AST(R"cc(
int* Pointer;
int* func(int*, int**);
void empty() {}
class Cls {
void method();
};
template <int X>
void funcTmpl(int*) {}
auto& FuncTmplSpec = funcTmpl<2>;
)cc");
auto &TU = *AST.context().getTranslationUnitDecl();
EXPECT_FALSE(isInferenceTarget(lookup("Pointer", TU)));
EXPECT_TRUE(isInferenceTarget(lookup("func", TU)));
EXPECT_TRUE(isInferenceTarget(lookup("empty", TU)));
auto &Cls = lookup<CXXRecordDecl>("Cls", TU);
EXPECT_FALSE(isInferenceTarget(Cls));
EXPECT_TRUE(isInferenceTarget(lookup("method", Cls)));
// A function template is not an inference target.
const FunctionTemplateDecl &FuncTmpl =
lookup<FunctionTemplateDecl>("funcTmpl", TU);
EXPECT_FALSE(isInferenceTarget(FuncTmpl));
EXPECT_FALSE(isInferenceTarget(*FuncTmpl.getTemplatedDecl()));
// The template specialization is *also* not an inference target.
const VarDecl &FuncTmplSpec = lookup<VarDecl>("FuncTmplSpec", TU);
EXPECT_FALSE(isInferenceTarget(FuncTmplSpec));
const ValueDecl &FuncTmpl2 =
*cast<DeclRefExpr>(FuncTmplSpec.getInit()->IgnoreImplicit())->getDecl();
EXPECT_FALSE(isInferenceTarget(FuncTmpl2));
}
TEST(InferableTest, CountInferableSlots) {
TestAST AST(R"cc(
using Pointer = int *;
template <class T>
struct S;
struct T;
void f1(int *);
void f2(Pointer);
void f3(int **);
void f4(Pointer *);
void f5(int *&);
void f6(int (*)()); // function pointer
int *g1(int);
Pointer g2(int);
void h1(S<int *>);
void h2(int T::*); // pointer to data member
void h3(int (T::*)()); // pointer to member function
)cc");
auto &TU = *AST.context().getTranslationUnitDecl();
// All the 'f's have a single pointer arg.
EXPECT_EQ(1, countInferableSlots(lookup("f1", TU)));
EXPECT_EQ(1, countInferableSlots(lookup("f2", TU)));
EXPECT_EQ(1, countInferableSlots(lookup("f3", TU)));
EXPECT_EQ(1, countInferableSlots(lookup("f4", TU)));
EXPECT_EQ(1, countInferableSlots(lookup("f5", TU)));
EXPECT_EQ(1, countInferableSlots(lookup("f6", TU)));
// All the 'g's have a pointer return.
EXPECT_EQ(1, countInferableSlots(lookup("g1", TU)));
EXPECT_EQ(1, countInferableSlots(lookup("g2", TU)));
// The 'h's have types that aren't really pointers.
EXPECT_EQ(0, countInferableSlots(lookup("h1", TU)));
EXPECT_EQ(0, countInferableSlots(lookup("h2", TU)));
EXPECT_EQ(0, countInferableSlots(lookup("h3", TU)));
}
} // namespace
} // namespace clang::tidy::nullability