110d95c53SHaojian Wu //=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
210d95c53SHaojian Wu //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610d95c53SHaojian Wu //
710d95c53SHaojian Wu //===----------------------------------------------------------------------===//
810d95c53SHaojian Wu 
910d95c53SHaojian Wu #include "clang/Frontend/CompilerInstance.h"
1010d95c53SHaojian Wu #include "clang/Frontend/FrontendActions.h"
1110d95c53SHaojian Wu #include "clang/Lex/Preprocessor.h"
1210d95c53SHaojian Wu #include "clang/Parse/ParseAST.h"
1310d95c53SHaojian Wu #include "clang/Sema/Sema.h"
1410d95c53SHaojian Wu #include "clang/Sema/SemaDiagnostic.h"
1510d95c53SHaojian Wu #include "clang/Tooling/Tooling.h"
166fae38ecSIlya Biryukov #include "llvm/Testing/Support/Annotations.h"
1710d95c53SHaojian Wu #include "gmock/gmock.h"
184974d75dSIlya Biryukov #include "gtest/gtest.h"
194974d75dSIlya Biryukov #include <cstddef>
204974d75dSIlya Biryukov #include <string>
2110d95c53SHaojian Wu 
2210d95c53SHaojian Wu namespace {
2310d95c53SHaojian Wu 
2410d95c53SHaojian Wu using namespace clang;
2510d95c53SHaojian Wu using namespace clang::tooling;
264974d75dSIlya Biryukov using ::testing::Each;
2710d95c53SHaojian Wu using ::testing::UnorderedElementsAre;
2810d95c53SHaojian Wu 
2910d95c53SHaojian Wu const char TestCCName[] = "test.cc";
304974d75dSIlya Biryukov 
314974d75dSIlya Biryukov struct CompletionContext {
324974d75dSIlya Biryukov   std::vector<std::string> VisitedNamespaces;
334974d75dSIlya Biryukov   std::string PreferredType;
341d7ba831SIlya Biryukov   // String representation of std::ptrdiff_t on a given platform. This is a hack
351d7ba831SIlya Biryukov   // to properly account for different configurations of clang.
361d7ba831SIlya Biryukov   std::string PtrDiffType;
374974d75dSIlya Biryukov };
3810d95c53SHaojian Wu 
3910d95c53SHaojian Wu class VisitedContextFinder : public CodeCompleteConsumer {
4010d95c53SHaojian Wu public:
VisitedContextFinder(CompletionContext & ResultCtx)414974d75dSIlya Biryukov   VisitedContextFinder(CompletionContext &ResultCtx)
423a75330fSSam McCall       : CodeCompleteConsumer(/*CodeCompleteOpts=*/{}), ResultCtx(ResultCtx),
4310d95c53SHaojian Wu         CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
4410d95c53SHaojian Wu 
ProcessCodeCompleteResults(Sema & S,CodeCompletionContext Context,CodeCompletionResult * Results,unsigned NumResults)4510d95c53SHaojian Wu   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
4610d95c53SHaojian Wu                                   CodeCompletionResult *Results,
4710d95c53SHaojian Wu                                   unsigned NumResults) override {
484974d75dSIlya Biryukov     ResultCtx.VisitedNamespaces =
494974d75dSIlya Biryukov         getVisitedNamespace(Context.getVisitedContexts());
504974d75dSIlya Biryukov     ResultCtx.PreferredType = Context.getPreferredType().getAsString();
511d7ba831SIlya Biryukov     ResultCtx.PtrDiffType =
521d7ba831SIlya Biryukov         S.getASTContext().getPointerDiffType().getAsString();
5310d95c53SHaojian Wu   }
5410d95c53SHaojian Wu 
getAllocator()5510d95c53SHaojian Wu   CodeCompletionAllocator &getAllocator() override {
5610d95c53SHaojian Wu     return CCTUInfo.getAllocator();
5710d95c53SHaojian Wu   }
5810d95c53SHaojian Wu 
getCodeCompletionTUInfo()5910d95c53SHaojian Wu   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
6010d95c53SHaojian Wu 
614974d75dSIlya Biryukov private:
getVisitedNamespace(CodeCompletionContext::VisitedContextSet VisitedContexts) const624974d75dSIlya Biryukov   std::vector<std::string> getVisitedNamespace(
634974d75dSIlya Biryukov       CodeCompletionContext::VisitedContextSet VisitedContexts) const {
6410d95c53SHaojian Wu     std::vector<std::string> NSNames;
6510d95c53SHaojian Wu     for (const auto *Context : VisitedContexts)
6610d95c53SHaojian Wu       if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
6710d95c53SHaojian Wu         NSNames.push_back(NS->getQualifiedNameAsString());
6810d95c53SHaojian Wu     return NSNames;
6910d95c53SHaojian Wu   }
7010d95c53SHaojian Wu 
714974d75dSIlya Biryukov   CompletionContext &ResultCtx;
7210d95c53SHaojian Wu   CodeCompletionTUInfo CCTUInfo;
7310d95c53SHaojian Wu };
7410d95c53SHaojian Wu 
7510d95c53SHaojian Wu class CodeCompleteAction : public SyntaxOnlyAction {
7610d95c53SHaojian Wu public:
CodeCompleteAction(ParsedSourceLocation P,CompletionContext & ResultCtx)774974d75dSIlya Biryukov   CodeCompleteAction(ParsedSourceLocation P, CompletionContext &ResultCtx)
784974d75dSIlya Biryukov       : CompletePosition(std::move(P)), ResultCtx(ResultCtx) {}
7910d95c53SHaojian Wu 
BeginInvocation(CompilerInstance & CI)8010d95c53SHaojian Wu   bool BeginInvocation(CompilerInstance &CI) override {
8110d95c53SHaojian Wu     CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
824974d75dSIlya Biryukov     CI.setCodeCompletionConsumer(new VisitedContextFinder(ResultCtx));
8310d95c53SHaojian Wu     return true;
8410d95c53SHaojian Wu   }
8510d95c53SHaojian Wu 
8610d95c53SHaojian Wu private:
8710d95c53SHaojian Wu   // 1-based code complete position <Line, Col>;
8810d95c53SHaojian Wu   ParsedSourceLocation CompletePosition;
894974d75dSIlya Biryukov   CompletionContext &ResultCtx;
9010d95c53SHaojian Wu };
9110d95c53SHaojian Wu 
offsetToPosition(llvm::StringRef Code,size_t Offset)9210d95c53SHaojian Wu ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
9310d95c53SHaojian Wu   Offset = std::min(Code.size(), Offset);
9410d95c53SHaojian Wu   StringRef Before = Code.substr(0, Offset);
9510d95c53SHaojian Wu   int Lines = Before.count('\n');
9610d95c53SHaojian Wu   size_t PrevNL = Before.rfind('\n');
9710d95c53SHaojian Wu   size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
9810d95c53SHaojian Wu   return {TestCCName, static_cast<unsigned>(Lines + 1),
9910d95c53SHaojian Wu           static_cast<unsigned>(Offset - StartOfLine + 1)};
10010d95c53SHaojian Wu }
10110d95c53SHaojian Wu 
runCompletion(StringRef Code,size_t Offset)1024974d75dSIlya Biryukov CompletionContext runCompletion(StringRef Code, size_t Offset) {
1034974d75dSIlya Biryukov   CompletionContext ResultCtx;
104b22804b3SDmitri Gribenko   clang::tooling::runToolOnCodeWithArgs(
105b22804b3SDmitri Gribenko       std::make_unique<CodeCompleteAction>(offsetToPosition(Code, Offset),
106b22804b3SDmitri Gribenko                                            ResultCtx),
107b22804b3SDmitri Gribenko       Code, {"-std=c++11"}, TestCCName);
1084974d75dSIlya Biryukov   return ResultCtx;
1094974d75dSIlya Biryukov }
1104974d75dSIlya Biryukov 
runCodeCompleteOnCode(StringRef AnnotatedCode)1114974d75dSIlya Biryukov CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
1126fae38ecSIlya Biryukov   llvm::Annotations A(AnnotatedCode);
1136fae38ecSIlya Biryukov   return runCompletion(A.code(), A.point());
1144974d75dSIlya Biryukov }
1154974d75dSIlya Biryukov 
1161d7ba831SIlya Biryukov std::vector<std::string>
collectPreferredTypes(StringRef AnnotatedCode,std::string * PtrDiffType=nullptr)1171d7ba831SIlya Biryukov collectPreferredTypes(StringRef AnnotatedCode,
1181d7ba831SIlya Biryukov                       std::string *PtrDiffType = nullptr) {
1196fae38ecSIlya Biryukov   llvm::Annotations A(AnnotatedCode);
1204974d75dSIlya Biryukov   std::vector<std::string> Types;
1216fae38ecSIlya Biryukov   for (size_t Point : A.points()) {
1226fae38ecSIlya Biryukov     auto Results = runCompletion(A.code(), Point);
1231d7ba831SIlya Biryukov     if (PtrDiffType) {
1241d7ba831SIlya Biryukov       assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType);
1251d7ba831SIlya Biryukov       *PtrDiffType = Results.PtrDiffType;
1261d7ba831SIlya Biryukov     }
1271d7ba831SIlya Biryukov     Types.push_back(Results.PreferredType);
1281d7ba831SIlya Biryukov   }
1294974d75dSIlya Biryukov   return Types;
13010d95c53SHaojian Wu }
13110d95c53SHaojian Wu 
TEST(SemaCodeCompleteTest,VisitedNSForValidQualifiedId)13210d95c53SHaojian Wu TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
13310d95c53SHaojian Wu   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
13410d95c53SHaojian Wu      namespace ns1 {}
13510d95c53SHaojian Wu      namespace ns2 {}
13610d95c53SHaojian Wu      namespace ns3 {}
13710d95c53SHaojian Wu      namespace ns3 { namespace nns3 {} }
13810d95c53SHaojian Wu 
13910d95c53SHaojian Wu      namespace foo {
14010d95c53SHaojian Wu      using namespace ns1;
14110d95c53SHaojian Wu      namespace ns4 {} // not visited
14210d95c53SHaojian Wu      namespace { using namespace ns2; }
14310d95c53SHaojian Wu      inline namespace bar { using namespace ns3::nns3; }
14410d95c53SHaojian Wu      } // foo
14510d95c53SHaojian Wu      namespace ns { foo::^ }
1464974d75dSIlya Biryukov   )cpp")
1474974d75dSIlya Biryukov                        .VisitedNamespaces;
14810d95c53SHaojian Wu   EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
14910d95c53SHaojian Wu                                               "foo::(anonymous)"));
15010d95c53SHaojian Wu }
15110d95c53SHaojian Wu 
TEST(SemaCodeCompleteTest,VisitedNSForInvalidQualifiedId)152206740e7SEric Liu TEST(SemaCodeCompleteTest, VisitedNSForInvalidQualifiedId) {
15310d95c53SHaojian Wu   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
154206740e7SEric Liu      namespace na {}
155206740e7SEric Liu      namespace ns1 {
156206740e7SEric Liu      using namespace na;
157206740e7SEric Liu      foo::^
158206740e7SEric Liu      }
1594974d75dSIlya Biryukov   )cpp")
1604974d75dSIlya Biryukov                        .VisitedNamespaces;
161206740e7SEric Liu   EXPECT_THAT(VisitedNS, UnorderedElementsAre("ns1", "na"));
16210d95c53SHaojian Wu }
16310d95c53SHaojian Wu 
TEST(SemaCodeCompleteTest,VisitedNSWithoutQualifier)164f5ba09f7SEric Liu TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
165f5ba09f7SEric Liu   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
166f5ba09f7SEric Liu     namespace n1 {
167f5ba09f7SEric Liu     namespace n2 {
168f5ba09f7SEric Liu       void f(^) {}
169f5ba09f7SEric Liu     }
170f5ba09f7SEric Liu     }
1714974d75dSIlya Biryukov   )cpp")
1724974d75dSIlya Biryukov                        .VisitedNamespaces;
173f5ba09f7SEric Liu   EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));
174f5ba09f7SEric Liu }
175f5ba09f7SEric Liu 
TEST(PreferredTypeTest,BinaryExpr)1764974d75dSIlya Biryukov TEST(PreferredTypeTest, BinaryExpr) {
1774974d75dSIlya Biryukov   // Check various operations for arithmetic types.
17869e181d4SIlya Biryukov   StringRef Code = R"cpp(
1794974d75dSIlya Biryukov     void test(int x) {
1804974d75dSIlya Biryukov       x = ^10;
1814974d75dSIlya Biryukov       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
1824974d75dSIlya Biryukov       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
1830250e29eSDavid Green     })cpp";
18469e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
18569e181d4SIlya Biryukov 
18669e181d4SIlya Biryukov   Code = R"cpp(
1874974d75dSIlya Biryukov     void test(float x) {
1884974d75dSIlya Biryukov       x = ^10;
1894974d75dSIlya Biryukov       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
1904974d75dSIlya Biryukov       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
1910250e29eSDavid Green     })cpp";
19269e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("float"));
1934974d75dSIlya Biryukov 
1944974d75dSIlya Biryukov   // Pointer types.
19569e181d4SIlya Biryukov   Code = R"cpp(
1964974d75dSIlya Biryukov     void test(int *ptr) {
1974974d75dSIlya Biryukov       ptr - ^ptr;
1984974d75dSIlya Biryukov       ptr = ^ptr;
1990250e29eSDavid Green     })cpp";
20069e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
2014974d75dSIlya Biryukov 
20269e181d4SIlya Biryukov   Code = R"cpp(
2034974d75dSIlya Biryukov     void test(int *ptr) {
2044974d75dSIlya Biryukov       ptr + ^10;
2054974d75dSIlya Biryukov       ptr += ^10;
2064974d75dSIlya Biryukov       ptr -= ^10;
2070250e29eSDavid Green     })cpp";
2081d7ba831SIlya Biryukov   {
2091d7ba831SIlya Biryukov     std::string PtrDiff;
2101d7ba831SIlya Biryukov     auto Types = collectPreferredTypes(Code, &PtrDiff);
2111d7ba831SIlya Biryukov     EXPECT_THAT(Types, Each(PtrDiff));
2121d7ba831SIlya Biryukov   }
2134974d75dSIlya Biryukov 
2144974d75dSIlya Biryukov   // Comparison operators.
21569e181d4SIlya Biryukov   Code = R"cpp(
2164974d75dSIlya Biryukov     void test(int i) {
2174974d75dSIlya Biryukov       i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;
2184974d75dSIlya Biryukov     }
2190250e29eSDavid Green   )cpp";
22069e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
2214974d75dSIlya Biryukov 
22269e181d4SIlya Biryukov   Code = R"cpp(
2234974d75dSIlya Biryukov     void test(int *ptr) {
2244974d75dSIlya Biryukov       ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;
2254974d75dSIlya Biryukov       ptr == ^ptr; ptr != ^ptr;
2264974d75dSIlya Biryukov     }
2270250e29eSDavid Green   )cpp";
22869e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
2294974d75dSIlya Biryukov 
2304974d75dSIlya Biryukov   // Relational operations.
23169e181d4SIlya Biryukov   Code = R"cpp(
2324974d75dSIlya Biryukov     void test(int i, int *ptr) {
2334974d75dSIlya Biryukov       i && ^1; i || ^1;
2344974d75dSIlya Biryukov       ptr && ^1; ptr || ^1;
2354974d75dSIlya Biryukov     }
2360250e29eSDavid Green   )cpp";
23769e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
2384974d75dSIlya Biryukov 
2394974d75dSIlya Biryukov   // Bitwise operations.
24069e181d4SIlya Biryukov   Code = R"cpp(
2414974d75dSIlya Biryukov     void test(long long ll) {
2424974d75dSIlya Biryukov       ll | ^1; ll & ^1;
2434974d75dSIlya Biryukov     }
2440250e29eSDavid Green   )cpp";
24569e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
2464974d75dSIlya Biryukov 
24769e181d4SIlya Biryukov   Code = R"cpp(
2484974d75dSIlya Biryukov     enum A {};
2494974d75dSIlya Biryukov     void test(A a) {
2504974d75dSIlya Biryukov       a | ^1; a & ^1;
2514974d75dSIlya Biryukov     }
2520250e29eSDavid Green   )cpp";
253*888673b6SJonas Devlieghere   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
2544974d75dSIlya Biryukov 
25569e181d4SIlya Biryukov   Code = R"cpp(
2564974d75dSIlya Biryukov     enum class A {};
2574974d75dSIlya Biryukov     void test(A a) {
2584974d75dSIlya Biryukov       // This is technically illegal with the 'enum class' without overloaded
2594974d75dSIlya Biryukov       // operators, but we pretend it's fine.
2604974d75dSIlya Biryukov       a | ^a; a & ^a;
2614974d75dSIlya Biryukov     }
2620250e29eSDavid Green   )cpp";
263*888673b6SJonas Devlieghere   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
2644974d75dSIlya Biryukov 
2654974d75dSIlya Biryukov   // Binary shifts.
26669e181d4SIlya Biryukov   Code = R"cpp(
2674974d75dSIlya Biryukov     void test(int i, long long ll) {
2684974d75dSIlya Biryukov       i << ^1; ll << ^1;
2694974d75dSIlya Biryukov       i <<= ^1; i <<= ^1;
2704974d75dSIlya Biryukov       i >> ^1; ll >> ^1;
2714974d75dSIlya Biryukov       i >>= ^1; i >>= ^1;
2724974d75dSIlya Biryukov     }
2730250e29eSDavid Green   )cpp";
27469e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
2754974d75dSIlya Biryukov 
2764974d75dSIlya Biryukov   // Comma does not provide any useful information.
27769e181d4SIlya Biryukov   Code = R"cpp(
2784974d75dSIlya Biryukov     class Cls {};
2794974d75dSIlya Biryukov     void test(int i, int* ptr, Cls x) {
2804974d75dSIlya Biryukov       (i, ^i);
2814974d75dSIlya Biryukov       (ptr, ^ptr);
2824974d75dSIlya Biryukov       (x, ^x);
2834974d75dSIlya Biryukov     }
2840250e29eSDavid Green   )cpp";
28569e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
2864974d75dSIlya Biryukov 
2874974d75dSIlya Biryukov   // User-defined types do not take operator overloading into account.
2884974d75dSIlya Biryukov   // However, they provide heuristics for some common cases.
28969e181d4SIlya Biryukov   Code = R"cpp(
2904974d75dSIlya Biryukov     class Cls {};
2914974d75dSIlya Biryukov     void test(Cls c) {
2924974d75dSIlya Biryukov       // we assume arithmetic and comparions ops take the same type.
2934974d75dSIlya Biryukov       c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;
2944974d75dSIlya Biryukov       c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;
2954974d75dSIlya Biryukov       // same for the assignments.
2964974d75dSIlya Biryukov       c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;
2974974d75dSIlya Biryukov     }
2980250e29eSDavid Green   )cpp";
299*888673b6SJonas Devlieghere   EXPECT_THAT(collectPreferredTypes(Code), Each("class Cls"));
3004974d75dSIlya Biryukov 
30169e181d4SIlya Biryukov   Code = R"cpp(
3024974d75dSIlya Biryukov     class Cls {};
3034974d75dSIlya Biryukov     void test(Cls c) {
3044974d75dSIlya Biryukov       // we assume relational ops operate on bools.
3054974d75dSIlya Biryukov       c && ^c; c || ^c;
3064974d75dSIlya Biryukov     }
3070250e29eSDavid Green   )cpp";
30869e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
3094974d75dSIlya Biryukov 
31069e181d4SIlya Biryukov   Code = R"cpp(
3114974d75dSIlya Biryukov     class Cls {};
3124974d75dSIlya Biryukov     void test(Cls c) {
3134974d75dSIlya Biryukov       // we make no assumptions about the following operators, since they are
3144974d75dSIlya Biryukov       // often overloaded with a non-standard meaning.
3154974d75dSIlya Biryukov       c << ^c; c >> ^c; c | ^c; c & ^c;
3164974d75dSIlya Biryukov       c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;
3174974d75dSIlya Biryukov     }
3180250e29eSDavid Green   )cpp";
31969e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
3204974d75dSIlya Biryukov }
3214974d75dSIlya Biryukov 
TEST(PreferredTypeTest,Members)3224f9543b4SIlya Biryukov TEST(PreferredTypeTest, Members) {
3234f9543b4SIlya Biryukov   StringRef Code = R"cpp(
3244f9543b4SIlya Biryukov     struct vector {
3254f9543b4SIlya Biryukov       int *begin();
3264f9543b4SIlya Biryukov       vector clone();
3274f9543b4SIlya Biryukov     };
3284f9543b4SIlya Biryukov 
3294f9543b4SIlya Biryukov     void test(int *a) {
3304f9543b4SIlya Biryukov       a = ^vector().^clone().^begin();
3314f9543b4SIlya Biryukov     }
3324f9543b4SIlya Biryukov   )cpp";
3334f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
3344f9543b4SIlya Biryukov }
3354f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,Conditions)3364f9543b4SIlya Biryukov TEST(PreferredTypeTest, Conditions) {
3374f9543b4SIlya Biryukov   StringRef Code = R"cpp(
3384f9543b4SIlya Biryukov     struct vector {
3394f9543b4SIlya Biryukov       bool empty();
3404f9543b4SIlya Biryukov     };
3414f9543b4SIlya Biryukov 
3424f9543b4SIlya Biryukov     void test() {
3434f9543b4SIlya Biryukov       if (^vector().^empty()) {}
3444f9543b4SIlya Biryukov       while (^vector().^empty()) {}
3454f9543b4SIlya Biryukov       for (; ^vector().^empty();) {}
3464f9543b4SIlya Biryukov     }
3474f9543b4SIlya Biryukov   )cpp";
3484f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
3494f9543b4SIlya Biryukov }
3504f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,InitAndAssignment)3514f9543b4SIlya Biryukov TEST(PreferredTypeTest, InitAndAssignment) {
3524f9543b4SIlya Biryukov   StringRef Code = R"cpp(
3534f9543b4SIlya Biryukov     struct vector {
3544f9543b4SIlya Biryukov       int* begin();
3554f9543b4SIlya Biryukov     };
3564f9543b4SIlya Biryukov 
3574f9543b4SIlya Biryukov     void test() {
3584f9543b4SIlya Biryukov       const int* x = ^vector().^begin();
3594f9543b4SIlya Biryukov       x = ^vector().^begin();
3604f9543b4SIlya Biryukov 
3614f9543b4SIlya Biryukov       if (const int* y = ^vector().^begin()) {}
3624f9543b4SIlya Biryukov     }
3634f9543b4SIlya Biryukov   )cpp";
3644f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
3654f9543b4SIlya Biryukov }
3664f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,UnaryExprs)3674f9543b4SIlya Biryukov TEST(PreferredTypeTest, UnaryExprs) {
3684f9543b4SIlya Biryukov   StringRef Code = R"cpp(
3694f9543b4SIlya Biryukov     void test(long long a) {
3704f9543b4SIlya Biryukov       a = +^a;
3714f9543b4SIlya Biryukov       a = -^a
3724f9543b4SIlya Biryukov       a = ++^a;
3734f9543b4SIlya Biryukov       a = --^a;
3744f9543b4SIlya Biryukov     }
3754f9543b4SIlya Biryukov   )cpp";
3764f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
3774f9543b4SIlya Biryukov 
3784f9543b4SIlya Biryukov   Code = R"cpp(
3794f9543b4SIlya Biryukov     void test(int a, int *ptr) {
3804f9543b4SIlya Biryukov       !^a;
3814f9543b4SIlya Biryukov       !^ptr;
3824f9543b4SIlya Biryukov       !!!^a;
3834f9543b4SIlya Biryukov 
3844f9543b4SIlya Biryukov       a = !^a;
3854f9543b4SIlya Biryukov       a = !^ptr;
3864f9543b4SIlya Biryukov       a = !!!^a;
3874f9543b4SIlya Biryukov     }
3884f9543b4SIlya Biryukov   )cpp";
3894f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
3904f9543b4SIlya Biryukov 
3914f9543b4SIlya Biryukov   Code = R"cpp(
3924f9543b4SIlya Biryukov     void test(int a) {
3934f9543b4SIlya Biryukov       const int* x = &^a;
3944f9543b4SIlya Biryukov     }
3954f9543b4SIlya Biryukov   )cpp";
3964f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int"));
3974f9543b4SIlya Biryukov 
3984f9543b4SIlya Biryukov   Code = R"cpp(
3994f9543b4SIlya Biryukov     void test(int *a) {
4004f9543b4SIlya Biryukov       int x = *^a;
4014f9543b4SIlya Biryukov       int &r = *^a;
4024f9543b4SIlya Biryukov     }
4034f9543b4SIlya Biryukov   )cpp";
4044f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
4054f9543b4SIlya Biryukov 
4064f9543b4SIlya Biryukov   Code = R"cpp(
4074f9543b4SIlya Biryukov     void test(int a) {
4084f9543b4SIlya Biryukov       *^a;
4094f9543b4SIlya Biryukov       &^a;
4104f9543b4SIlya Biryukov     }
4114f9543b4SIlya Biryukov 
4124f9543b4SIlya Biryukov   )cpp";
4134f9543b4SIlya Biryukov }
4144f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,ParenExpr)4154f9543b4SIlya Biryukov TEST(PreferredTypeTest, ParenExpr) {
4164f9543b4SIlya Biryukov   StringRef Code = R"cpp(
4174f9543b4SIlya Biryukov     const int *i = ^(^(^(^10)));
4184f9543b4SIlya Biryukov   )cpp";
4194f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
4204f9543b4SIlya Biryukov }
421ff2a9975SIlya Biryukov 
TEST(PreferredTypeTest,FunctionArguments)422ff2a9975SIlya Biryukov TEST(PreferredTypeTest, FunctionArguments) {
423ff2a9975SIlya Biryukov   StringRef Code = R"cpp(
424ff2a9975SIlya Biryukov     void foo(const int*);
425ff2a9975SIlya Biryukov 
426ff2a9975SIlya Biryukov     void bar(const int*);
427ff2a9975SIlya Biryukov     void bar(const int*, int b);
428ff2a9975SIlya Biryukov 
429ff2a9975SIlya Biryukov     struct vector {
430ff2a9975SIlya Biryukov       const int *data();
431ff2a9975SIlya Biryukov     };
432ff2a9975SIlya Biryukov     void test() {
433ff2a9975SIlya Biryukov       foo(^(^(^(^vec^tor^().^da^ta^()))));
434ff2a9975SIlya Biryukov       bar(^(^(^(^vec^tor^().^da^ta^()))));
435ff2a9975SIlya Biryukov     }
436ff2a9975SIlya Biryukov   )cpp";
437ff2a9975SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
438ff2a9975SIlya Biryukov 
439ff2a9975SIlya Biryukov   Code = R"cpp(
440ff2a9975SIlya Biryukov     void bar(int, volatile double *);
441ff2a9975SIlya Biryukov     void bar(int, volatile double *, int, int);
442ff2a9975SIlya Biryukov 
443ff2a9975SIlya Biryukov     struct vector {
444ff2a9975SIlya Biryukov       double *data();
445ff2a9975SIlya Biryukov     };
446ff2a9975SIlya Biryukov 
447ff2a9975SIlya Biryukov     struct class_members {
448ff2a9975SIlya Biryukov       void bar(int, volatile double *);
449ff2a9975SIlya Biryukov       void bar(int, volatile double *, int, int);
450ff2a9975SIlya Biryukov     };
451ff2a9975SIlya Biryukov     void test() {
452ff2a9975SIlya Biryukov       bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
453ff2a9975SIlya Biryukov       class_members().bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
454ff2a9975SIlya Biryukov     }
455ff2a9975SIlya Biryukov   )cpp";
456ff2a9975SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("volatile double *"));
457b1296faeSIlya Biryukov 
458b1296faeSIlya Biryukov   Code = R"cpp(
459b1296faeSIlya Biryukov     namespace ns {
460b1296faeSIlya Biryukov       struct vector {
461b1296faeSIlya Biryukov       };
462b1296faeSIlya Biryukov     }
463b1296faeSIlya Biryukov     void accepts_vector(ns::vector);
464b1296faeSIlya Biryukov 
465b1296faeSIlya Biryukov     void test() {
466b1296faeSIlya Biryukov       accepts_vector(^::^ns::^vector());
467b1296faeSIlya Biryukov     }
468b1296faeSIlya Biryukov   )cpp";
469b1296faeSIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("ns::vector"));
470b1296faeSIlya Biryukov 
471b1296faeSIlya Biryukov   Code = R"cpp(
472b1296faeSIlya Biryukov     template <class T>
473b1296faeSIlya Biryukov     struct vector { using self = vector; };
474b1296faeSIlya Biryukov 
475b1296faeSIlya Biryukov     void accepts_vector(vector<int>);
476b1296faeSIlya Biryukov     int foo(int);
477b1296faeSIlya Biryukov 
478b1296faeSIlya Biryukov     void test() {
479b1296faeSIlya Biryukov       accepts_vector(^::^vector<decltype(foo(1))>::^self);
480b1296faeSIlya Biryukov     }
481b1296faeSIlya Biryukov   )cpp";
482b1296faeSIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("vector<int>"));
483ff2a9975SIlya Biryukov }
484f7c8ace4SIlya Biryukov 
TEST(PreferredTypeTest,NoCrashOnInvalidTypes)485f7c8ace4SIlya Biryukov TEST(PreferredTypeTest, NoCrashOnInvalidTypes) {
486f7c8ace4SIlya Biryukov   StringRef Code = R"cpp(
487f7c8ace4SIlya Biryukov     auto x = decltype(&1)(^);
488f7c8ace4SIlya Biryukov     auto y = new decltype(&1)(^);
4896f428e09SHaojian Wu     // GNU decimal type extension is not supported in clang.
4906f428e09SHaojian Wu     auto z = new _Decimal128(^);
491f7431849SKadir Cetinkaya     void foo() { (void)(foo)(^); }
492f7c8ace4SIlya Biryukov   )cpp";
49362dea6e9SHaojian Wu   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
494f7c8ace4SIlya Biryukov }
4956f428e09SHaojian Wu 
49610d95c53SHaojian Wu } // namespace
497