xref: /llvm-project/clang/unittests/Sema/CodeCompleteTest.cpp (revision 23ef8bf9c0f338ee073c6c1b553c42e46d2f22ad)
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"
163432f4bfSJordan Rupprecht #include "llvm/Testing/Annotations/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;
260e00611cSTom Praschan using ::testing::AllOf;
270e00611cSTom Praschan using ::testing::Contains;
284974d75dSIlya Biryukov using ::testing::Each;
2910d95c53SHaojian Wu using ::testing::UnorderedElementsAre;
3010d95c53SHaojian Wu 
3110d95c53SHaojian Wu const char TestCCName[] = "test.cc";
324974d75dSIlya Biryukov 
334974d75dSIlya Biryukov struct CompletionContext {
344974d75dSIlya Biryukov   std::vector<std::string> VisitedNamespaces;
354974d75dSIlya Biryukov   std::string PreferredType;
361d7ba831SIlya Biryukov   // String representation of std::ptrdiff_t on a given platform. This is a hack
371d7ba831SIlya Biryukov   // to properly account for different configurations of clang.
381d7ba831SIlya Biryukov   std::string PtrDiffType;
394974d75dSIlya Biryukov };
4010d95c53SHaojian Wu 
410e00611cSTom Praschan struct CompletedFunctionDecl {
420e00611cSTom Praschan   std::string Name;
430e00611cSTom Praschan   bool IsStatic;
440e00611cSTom Praschan   bool CanBeCall;
450e00611cSTom Praschan };
460e00611cSTom Praschan MATCHER_P(named, name, "") { return arg.Name == name; }
470e00611cSTom Praschan MATCHER_P(isStatic, value, "") { return arg.IsStatic == value; }
480e00611cSTom Praschan MATCHER_P(canBeCall, value, "") { return arg.CanBeCall == value; }
490e00611cSTom Praschan 
500e00611cSTom Praschan class SaveCompletedFunctions : public CodeCompleteConsumer {
510e00611cSTom Praschan public:
SaveCompletedFunctions(std::vector<CompletedFunctionDecl> & CompletedFuncDecls)520e00611cSTom Praschan   SaveCompletedFunctions(std::vector<CompletedFunctionDecl> &CompletedFuncDecls)
530e00611cSTom Praschan       : CodeCompleteConsumer(/*CodeCompleteOpts=*/{}),
540e00611cSTom Praschan         CompletedFuncDecls(CompletedFuncDecls),
550e00611cSTom Praschan         CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
560e00611cSTom Praschan 
ProcessCodeCompleteResults(Sema & S,CodeCompletionContext Context,CodeCompletionResult * Results,unsigned NumResults)570e00611cSTom Praschan   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
580e00611cSTom Praschan                                   CodeCompletionResult *Results,
590e00611cSTom Praschan                                   unsigned NumResults) override {
600e00611cSTom Praschan     for (unsigned I = 0; I < NumResults; ++I) {
610e00611cSTom Praschan       auto R = Results[I];
620e00611cSTom Praschan       if (R.Kind == CodeCompletionResult::RK_Declaration) {
63*23ef8bf9SYounan Zhang         auto *ND = R.getDeclaration();
64*23ef8bf9SYounan Zhang         if (auto *Template = llvm::dyn_cast<FunctionTemplateDecl>(ND))
65*23ef8bf9SYounan Zhang           ND = Template->getTemplatedDecl();
66*23ef8bf9SYounan Zhang         if (const auto *FD = llvm::dyn_cast<FunctionDecl>(ND)) {
670e00611cSTom Praschan           CompletedFunctionDecl D;
680e00611cSTom Praschan           D.Name = FD->getNameAsString();
690e00611cSTom Praschan           D.CanBeCall = R.FunctionCanBeCall;
700e00611cSTom Praschan           D.IsStatic = FD->isStatic();
710e00611cSTom Praschan           CompletedFuncDecls.emplace_back(std::move(D));
720e00611cSTom Praschan         }
730e00611cSTom Praschan       }
740e00611cSTom Praschan     }
750e00611cSTom Praschan   }
760e00611cSTom Praschan 
770e00611cSTom Praschan private:
getAllocator()780e00611cSTom Praschan   CodeCompletionAllocator &getAllocator() override {
790e00611cSTom Praschan     return CCTUInfo.getAllocator();
800e00611cSTom Praschan   }
810e00611cSTom Praschan 
getCodeCompletionTUInfo()820e00611cSTom Praschan   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
830e00611cSTom Praschan 
840e00611cSTom Praschan   std::vector<CompletedFunctionDecl> &CompletedFuncDecls;
850e00611cSTom Praschan 
860e00611cSTom Praschan   CodeCompletionTUInfo CCTUInfo;
870e00611cSTom Praschan };
880e00611cSTom Praschan 
8910d95c53SHaojian Wu class VisitedContextFinder : public CodeCompleteConsumer {
9010d95c53SHaojian Wu public:
VisitedContextFinder(CompletionContext & ResultCtx)914974d75dSIlya Biryukov   VisitedContextFinder(CompletionContext &ResultCtx)
923a75330fSSam McCall       : CodeCompleteConsumer(/*CodeCompleteOpts=*/{}), ResultCtx(ResultCtx),
9310d95c53SHaojian Wu         CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
9410d95c53SHaojian Wu 
ProcessCodeCompleteResults(Sema & S,CodeCompletionContext Context,CodeCompletionResult * Results,unsigned NumResults)9510d95c53SHaojian Wu   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
9610d95c53SHaojian Wu                                   CodeCompletionResult *Results,
9710d95c53SHaojian Wu                                   unsigned NumResults) override {
984974d75dSIlya Biryukov     ResultCtx.VisitedNamespaces =
994974d75dSIlya Biryukov         getVisitedNamespace(Context.getVisitedContexts());
1004974d75dSIlya Biryukov     ResultCtx.PreferredType = Context.getPreferredType().getAsString();
1011d7ba831SIlya Biryukov     ResultCtx.PtrDiffType =
1021d7ba831SIlya Biryukov         S.getASTContext().getPointerDiffType().getAsString();
10310d95c53SHaojian Wu   }
10410d95c53SHaojian Wu 
getAllocator()10510d95c53SHaojian Wu   CodeCompletionAllocator &getAllocator() override {
10610d95c53SHaojian Wu     return CCTUInfo.getAllocator();
10710d95c53SHaojian Wu   }
10810d95c53SHaojian Wu 
getCodeCompletionTUInfo()10910d95c53SHaojian Wu   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
11010d95c53SHaojian Wu 
1114974d75dSIlya Biryukov private:
getVisitedNamespace(CodeCompletionContext::VisitedContextSet VisitedContexts) const1124974d75dSIlya Biryukov   std::vector<std::string> getVisitedNamespace(
1134974d75dSIlya Biryukov       CodeCompletionContext::VisitedContextSet VisitedContexts) const {
11410d95c53SHaojian Wu     std::vector<std::string> NSNames;
11510d95c53SHaojian Wu     for (const auto *Context : VisitedContexts)
11610d95c53SHaojian Wu       if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
11710d95c53SHaojian Wu         NSNames.push_back(NS->getQualifiedNameAsString());
11810d95c53SHaojian Wu     return NSNames;
11910d95c53SHaojian Wu   }
12010d95c53SHaojian Wu 
1214974d75dSIlya Biryukov   CompletionContext &ResultCtx;
12210d95c53SHaojian Wu   CodeCompletionTUInfo CCTUInfo;
12310d95c53SHaojian Wu };
12410d95c53SHaojian Wu 
12510d95c53SHaojian Wu class CodeCompleteAction : public SyntaxOnlyAction {
12610d95c53SHaojian Wu public:
CodeCompleteAction(ParsedSourceLocation P,CodeCompleteConsumer * Consumer)1270e00611cSTom Praschan   CodeCompleteAction(ParsedSourceLocation P, CodeCompleteConsumer *Consumer)
1280e00611cSTom Praschan       : CompletePosition(std::move(P)), Consumer(Consumer) {}
12910d95c53SHaojian Wu 
BeginInvocation(CompilerInstance & CI)13010d95c53SHaojian Wu   bool BeginInvocation(CompilerInstance &CI) override {
13110d95c53SHaojian Wu     CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
1320e00611cSTom Praschan     CI.setCodeCompletionConsumer(Consumer);
13310d95c53SHaojian Wu     return true;
13410d95c53SHaojian Wu   }
13510d95c53SHaojian Wu 
13610d95c53SHaojian Wu private:
13710d95c53SHaojian Wu   // 1-based code complete position <Line, Col>;
13810d95c53SHaojian Wu   ParsedSourceLocation CompletePosition;
1390e00611cSTom Praschan   CodeCompleteConsumer *Consumer;
14010d95c53SHaojian Wu };
14110d95c53SHaojian Wu 
offsetToPosition(llvm::StringRef Code,size_t Offset)14210d95c53SHaojian Wu ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
14310d95c53SHaojian Wu   Offset = std::min(Code.size(), Offset);
14410d95c53SHaojian Wu   StringRef Before = Code.substr(0, Offset);
14510d95c53SHaojian Wu   int Lines = Before.count('\n');
14610d95c53SHaojian Wu   size_t PrevNL = Before.rfind('\n');
14710d95c53SHaojian Wu   size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
14810d95c53SHaojian Wu   return {TestCCName, static_cast<unsigned>(Lines + 1),
14910d95c53SHaojian Wu           static_cast<unsigned>(Offset - StartOfLine + 1)};
15010d95c53SHaojian Wu }
15110d95c53SHaojian Wu 
runCompletion(StringRef Code,size_t Offset)1524974d75dSIlya Biryukov CompletionContext runCompletion(StringRef Code, size_t Offset) {
1534974d75dSIlya Biryukov   CompletionContext ResultCtx;
154b22804b3SDmitri Gribenko   clang::tooling::runToolOnCodeWithArgs(
155b22804b3SDmitri Gribenko       std::make_unique<CodeCompleteAction>(offsetToPosition(Code, Offset),
1560e00611cSTom Praschan                                            new VisitedContextFinder(ResultCtx)),
157b22804b3SDmitri Gribenko       Code, {"-std=c++11"}, TestCCName);
1584974d75dSIlya Biryukov   return ResultCtx;
1594974d75dSIlya Biryukov }
1604974d75dSIlya Biryukov 
runCodeCompleteOnCode(StringRef AnnotatedCode)1614974d75dSIlya Biryukov CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
1626fae38ecSIlya Biryukov   llvm::Annotations A(AnnotatedCode);
1636fae38ecSIlya Biryukov   return runCompletion(A.code(), A.point());
1644974d75dSIlya Biryukov }
1654974d75dSIlya Biryukov 
1661d7ba831SIlya Biryukov std::vector<std::string>
collectPreferredTypes(StringRef AnnotatedCode,std::string * PtrDiffType=nullptr)1671d7ba831SIlya Biryukov collectPreferredTypes(StringRef AnnotatedCode,
1681d7ba831SIlya Biryukov                       std::string *PtrDiffType = nullptr) {
1696fae38ecSIlya Biryukov   llvm::Annotations A(AnnotatedCode);
1704974d75dSIlya Biryukov   std::vector<std::string> Types;
1716fae38ecSIlya Biryukov   for (size_t Point : A.points()) {
1726fae38ecSIlya Biryukov     auto Results = runCompletion(A.code(), Point);
1731d7ba831SIlya Biryukov     if (PtrDiffType) {
1741d7ba831SIlya Biryukov       assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType);
1751d7ba831SIlya Biryukov       *PtrDiffType = Results.PtrDiffType;
1761d7ba831SIlya Biryukov     }
1771d7ba831SIlya Biryukov     Types.push_back(Results.PreferredType);
1781d7ba831SIlya Biryukov   }
1794974d75dSIlya Biryukov   return Types;
18010d95c53SHaojian Wu }
18110d95c53SHaojian Wu 
1820e00611cSTom Praschan std::vector<CompletedFunctionDecl>
CollectCompletedFunctions(StringRef Code,std::size_t Point)1830e00611cSTom Praschan CollectCompletedFunctions(StringRef Code, std::size_t Point) {
1840e00611cSTom Praschan   std::vector<CompletedFunctionDecl> Result;
1850e00611cSTom Praschan   clang::tooling::runToolOnCodeWithArgs(
1860e00611cSTom Praschan       std::make_unique<CodeCompleteAction>(offsetToPosition(Code, Point),
1870e00611cSTom Praschan                                            new SaveCompletedFunctions(Result)),
1880e00611cSTom Praschan       Code, {"-std=c++11"}, TestCCName);
1890e00611cSTom Praschan   return Result;
1900e00611cSTom Praschan }
1910e00611cSTom Praschan 
TEST(SemaCodeCompleteTest,FunctionCanBeCall)1920e00611cSTom Praschan TEST(SemaCodeCompleteTest, FunctionCanBeCall) {
1930e00611cSTom Praschan   llvm::Annotations Code(R"cpp(
1940e00611cSTom Praschan     struct Foo {
1950e00611cSTom Praschan       static int staticMethod();
1960e00611cSTom Praschan       int method() const;
197*23ef8bf9SYounan Zhang       template <typename T, typename U, typename V = int>
198*23ef8bf9SYounan Zhang       T generic(U, V);
199*23ef8bf9SYounan Zhang       template <typename T, int U = 3>
200*23ef8bf9SYounan Zhang       static T staticGeneric();
2010e00611cSTom Praschan       Foo() {
2020e00611cSTom Praschan         this->$canBeCall^
2030e00611cSTom Praschan         $canBeCall^
2040e00611cSTom Praschan         Foo::$canBeCall^
2050e00611cSTom Praschan       }
2060e00611cSTom Praschan     };
2070e00611cSTom Praschan 
2080e00611cSTom Praschan     struct Derived : Foo {
209*23ef8bf9SYounan Zhang       using Foo::method;
210*23ef8bf9SYounan Zhang       using Foo::generic;
2110e00611cSTom Praschan       Derived() {
2120e00611cSTom Praschan         Foo::$canBeCall^
2130e00611cSTom Praschan       }
2140e00611cSTom Praschan     };
2150e00611cSTom Praschan 
2160e00611cSTom Praschan     struct OtherClass {
2170e00611cSTom Praschan       OtherClass() {
2180e00611cSTom Praschan         Foo f;
219*23ef8bf9SYounan Zhang         Derived d;
2200e00611cSTom Praschan         f.$canBeCall^
221*23ef8bf9SYounan Zhang         ; // Prevent parsing as 'f.f'
222*23ef8bf9SYounan Zhang         f.Foo::$canBeCall^
2230e00611cSTom Praschan         &Foo::$cannotBeCall^
224*23ef8bf9SYounan Zhang         ;
225*23ef8bf9SYounan Zhang         d.Foo::$canBeCall^
226*23ef8bf9SYounan Zhang         ;
227*23ef8bf9SYounan Zhang         d.Derived::$canBeCall^
2280e00611cSTom Praschan       }
2290e00611cSTom Praschan     };
2300e00611cSTom Praschan 
2310e00611cSTom Praschan     int main() {
2320e00611cSTom Praschan       Foo f;
233*23ef8bf9SYounan Zhang       Derived d;
2340e00611cSTom Praschan       f.$canBeCall^
235*23ef8bf9SYounan Zhang       ; // Prevent parsing as 'f.f'
236*23ef8bf9SYounan Zhang       f.Foo::$canBeCall^
2370e00611cSTom Praschan       &Foo::$cannotBeCall^
238*23ef8bf9SYounan Zhang       ;
239*23ef8bf9SYounan Zhang       d.Foo::$canBeCall^
240*23ef8bf9SYounan Zhang       ;
241*23ef8bf9SYounan Zhang       d.Derived::$canBeCall^
2420e00611cSTom Praschan     }
2430e00611cSTom Praschan     )cpp");
2440e00611cSTom Praschan 
2450e00611cSTom Praschan   for (const auto &P : Code.points("canBeCall")) {
2460e00611cSTom Praschan     auto Results = CollectCompletedFunctions(Code.code(), P);
2470e00611cSTom Praschan     EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
2480e00611cSTom Praschan                                         canBeCall(true))));
249*23ef8bf9SYounan Zhang     EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
250*23ef8bf9SYounan Zhang                                         canBeCall(true))));
2510e00611cSTom Praschan   }
2520e00611cSTom Praschan 
2530e00611cSTom Praschan   for (const auto &P : Code.points("cannotBeCall")) {
2540e00611cSTom Praschan     auto Results = CollectCompletedFunctions(Code.code(), P);
2550e00611cSTom Praschan     EXPECT_THAT(Results, Contains(AllOf(named("method"), isStatic(false),
2560e00611cSTom Praschan                                         canBeCall(false))));
257*23ef8bf9SYounan Zhang     EXPECT_THAT(Results, Contains(AllOf(named("generic"), isStatic(false),
258*23ef8bf9SYounan Zhang                                         canBeCall(false))));
2590e00611cSTom Praschan   }
2600e00611cSTom Praschan 
2610e00611cSTom Praschan   // static method can always be a call
2620e00611cSTom Praschan   for (const auto &P : Code.points()) {
2630e00611cSTom Praschan     auto Results = CollectCompletedFunctions(Code.code(), P);
2640e00611cSTom Praschan     EXPECT_THAT(Results, Contains(AllOf(named("staticMethod"), isStatic(true),
2650e00611cSTom Praschan                                         canBeCall(true))));
266*23ef8bf9SYounan Zhang     EXPECT_THAT(Results, Contains(AllOf(named("staticGeneric"), isStatic(true),
267*23ef8bf9SYounan Zhang                                         canBeCall(true))));
2680e00611cSTom Praschan   }
2690e00611cSTom Praschan }
2700e00611cSTom Praschan 
TEST(SemaCodeCompleteTest,VisitedNSForValidQualifiedId)27110d95c53SHaojian Wu TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
27210d95c53SHaojian Wu   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
27310d95c53SHaojian Wu      namespace ns1 {}
27410d95c53SHaojian Wu      namespace ns2 {}
27510d95c53SHaojian Wu      namespace ns3 {}
27610d95c53SHaojian Wu      namespace ns3 { namespace nns3 {} }
27710d95c53SHaojian Wu 
27810d95c53SHaojian Wu      namespace foo {
27910d95c53SHaojian Wu      using namespace ns1;
28010d95c53SHaojian Wu      namespace ns4 {} // not visited
28110d95c53SHaojian Wu      namespace { using namespace ns2; }
28210d95c53SHaojian Wu      inline namespace bar { using namespace ns3::nns3; }
28310d95c53SHaojian Wu      } // foo
28410d95c53SHaojian Wu      namespace ns { foo::^ }
2854974d75dSIlya Biryukov   )cpp")
2864974d75dSIlya Biryukov                        .VisitedNamespaces;
28710d95c53SHaojian Wu   EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
28810d95c53SHaojian Wu                                               "foo::(anonymous)"));
28910d95c53SHaojian Wu }
29010d95c53SHaojian Wu 
TEST(SemaCodeCompleteTest,VisitedNSForInvalidQualifiedId)291206740e7SEric Liu TEST(SemaCodeCompleteTest, VisitedNSForInvalidQualifiedId) {
29210d95c53SHaojian Wu   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
293206740e7SEric Liu      namespace na {}
294206740e7SEric Liu      namespace ns1 {
295206740e7SEric Liu      using namespace na;
296206740e7SEric Liu      foo::^
297206740e7SEric Liu      }
2984974d75dSIlya Biryukov   )cpp")
2994974d75dSIlya Biryukov                        .VisitedNamespaces;
300206740e7SEric Liu   EXPECT_THAT(VisitedNS, UnorderedElementsAre("ns1", "na"));
30110d95c53SHaojian Wu }
30210d95c53SHaojian Wu 
TEST(SemaCodeCompleteTest,VisitedNSWithoutQualifier)303f5ba09f7SEric Liu TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
304f5ba09f7SEric Liu   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
305f5ba09f7SEric Liu     namespace n1 {
306f5ba09f7SEric Liu     namespace n2 {
307f5ba09f7SEric Liu       void f(^) {}
308f5ba09f7SEric Liu     }
309f5ba09f7SEric Liu     }
3104974d75dSIlya Biryukov   )cpp")
3114974d75dSIlya Biryukov                        .VisitedNamespaces;
312f5ba09f7SEric Liu   EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));
313f5ba09f7SEric Liu }
314f5ba09f7SEric Liu 
TEST(PreferredTypeTest,BinaryExpr)3154974d75dSIlya Biryukov TEST(PreferredTypeTest, BinaryExpr) {
3164974d75dSIlya Biryukov   // Check various operations for arithmetic types.
31769e181d4SIlya Biryukov   StringRef Code = R"cpp(
3184974d75dSIlya Biryukov     void test(int x) {
3194974d75dSIlya Biryukov       x = ^10;
3204974d75dSIlya Biryukov       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
3214974d75dSIlya Biryukov       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
3220250e29eSDavid Green     })cpp";
32369e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
32469e181d4SIlya Biryukov 
32569e181d4SIlya Biryukov   Code = R"cpp(
3264974d75dSIlya Biryukov     void test(float x) {
3274974d75dSIlya Biryukov       x = ^10;
3284974d75dSIlya Biryukov       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
3294974d75dSIlya Biryukov       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
3300250e29eSDavid Green     })cpp";
33169e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("float"));
3324974d75dSIlya Biryukov 
3334974d75dSIlya Biryukov   // Pointer types.
33469e181d4SIlya Biryukov   Code = R"cpp(
3354974d75dSIlya Biryukov     void test(int *ptr) {
3364974d75dSIlya Biryukov       ptr - ^ptr;
3374974d75dSIlya Biryukov       ptr = ^ptr;
3380250e29eSDavid Green     })cpp";
33969e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
3404974d75dSIlya Biryukov 
34169e181d4SIlya Biryukov   Code = R"cpp(
3424974d75dSIlya Biryukov     void test(int *ptr) {
3434974d75dSIlya Biryukov       ptr + ^10;
3444974d75dSIlya Biryukov       ptr += ^10;
3454974d75dSIlya Biryukov       ptr -= ^10;
3460250e29eSDavid Green     })cpp";
3471d7ba831SIlya Biryukov   {
3481d7ba831SIlya Biryukov     std::string PtrDiff;
3491d7ba831SIlya Biryukov     auto Types = collectPreferredTypes(Code, &PtrDiff);
3501d7ba831SIlya Biryukov     EXPECT_THAT(Types, Each(PtrDiff));
3511d7ba831SIlya Biryukov   }
3524974d75dSIlya Biryukov 
3534974d75dSIlya Biryukov   // Comparison operators.
35469e181d4SIlya Biryukov   Code = R"cpp(
3554974d75dSIlya Biryukov     void test(int i) {
3564974d75dSIlya Biryukov       i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;
3574974d75dSIlya Biryukov     }
3580250e29eSDavid Green   )cpp";
35969e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
3604974d75dSIlya Biryukov 
36169e181d4SIlya Biryukov   Code = R"cpp(
3624974d75dSIlya Biryukov     void test(int *ptr) {
3634974d75dSIlya Biryukov       ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;
3644974d75dSIlya Biryukov       ptr == ^ptr; ptr != ^ptr;
3654974d75dSIlya Biryukov     }
3660250e29eSDavid Green   )cpp";
36769e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
3684974d75dSIlya Biryukov 
3694974d75dSIlya Biryukov   // Relational operations.
37069e181d4SIlya Biryukov   Code = R"cpp(
3714974d75dSIlya Biryukov     void test(int i, int *ptr) {
3724974d75dSIlya Biryukov       i && ^1; i || ^1;
3734974d75dSIlya Biryukov       ptr && ^1; ptr || ^1;
3744974d75dSIlya Biryukov     }
3750250e29eSDavid Green   )cpp";
37669e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
3774974d75dSIlya Biryukov 
3784974d75dSIlya Biryukov   // Bitwise operations.
37969e181d4SIlya Biryukov   Code = R"cpp(
3804974d75dSIlya Biryukov     void test(long long ll) {
3814974d75dSIlya Biryukov       ll | ^1; ll & ^1;
3824974d75dSIlya Biryukov     }
3830250e29eSDavid Green   )cpp";
38469e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
3854974d75dSIlya Biryukov 
38669e181d4SIlya Biryukov   Code = R"cpp(
3874974d75dSIlya Biryukov     enum A {};
3884974d75dSIlya Biryukov     void test(A a) {
3894974d75dSIlya Biryukov       a | ^1; a & ^1;
3904974d75dSIlya Biryukov     }
3910250e29eSDavid Green   )cpp";
39215f3cd6bSMatheus Izvekov   EXPECT_THAT(collectPreferredTypes(Code), Each("A"));
3934974d75dSIlya Biryukov 
39469e181d4SIlya Biryukov   Code = R"cpp(
3954974d75dSIlya Biryukov     enum class A {};
3964974d75dSIlya Biryukov     void test(A a) {
3974974d75dSIlya Biryukov       // This is technically illegal with the 'enum class' without overloaded
3984974d75dSIlya Biryukov       // operators, but we pretend it's fine.
3994974d75dSIlya Biryukov       a | ^a; a & ^a;
4004974d75dSIlya Biryukov     }
4010250e29eSDavid Green   )cpp";
40215f3cd6bSMatheus Izvekov   EXPECT_THAT(collectPreferredTypes(Code), Each("A"));
4034974d75dSIlya Biryukov 
4044974d75dSIlya Biryukov   // Binary shifts.
40569e181d4SIlya Biryukov   Code = R"cpp(
4064974d75dSIlya Biryukov     void test(int i, long long ll) {
4074974d75dSIlya Biryukov       i << ^1; ll << ^1;
4084974d75dSIlya Biryukov       i <<= ^1; i <<= ^1;
4094974d75dSIlya Biryukov       i >> ^1; ll >> ^1;
4104974d75dSIlya Biryukov       i >>= ^1; i >>= ^1;
4114974d75dSIlya Biryukov     }
4120250e29eSDavid Green   )cpp";
41369e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
4144974d75dSIlya Biryukov 
4154974d75dSIlya Biryukov   // Comma does not provide any useful information.
41669e181d4SIlya Biryukov   Code = R"cpp(
4174974d75dSIlya Biryukov     class Cls {};
4184974d75dSIlya Biryukov     void test(int i, int* ptr, Cls x) {
4194974d75dSIlya Biryukov       (i, ^i);
4204974d75dSIlya Biryukov       (ptr, ^ptr);
4214974d75dSIlya Biryukov       (x, ^x);
4224974d75dSIlya Biryukov     }
4230250e29eSDavid Green   )cpp";
42469e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
4254974d75dSIlya Biryukov 
4264974d75dSIlya Biryukov   // User-defined types do not take operator overloading into account.
4274974d75dSIlya Biryukov   // However, they provide heuristics for some common cases.
42869e181d4SIlya Biryukov   Code = R"cpp(
4294974d75dSIlya Biryukov     class Cls {};
4304974d75dSIlya Biryukov     void test(Cls c) {
4314974d75dSIlya Biryukov       // we assume arithmetic and comparions ops take the same type.
4324974d75dSIlya Biryukov       c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;
4334974d75dSIlya Biryukov       c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;
4344974d75dSIlya Biryukov       // same for the assignments.
4354974d75dSIlya Biryukov       c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;
4364974d75dSIlya Biryukov     }
4370250e29eSDavid Green   )cpp";
43815f3cd6bSMatheus Izvekov   EXPECT_THAT(collectPreferredTypes(Code), Each("Cls"));
4394974d75dSIlya Biryukov 
44069e181d4SIlya Biryukov   Code = R"cpp(
4414974d75dSIlya Biryukov     class Cls {};
4424974d75dSIlya Biryukov     void test(Cls c) {
4434974d75dSIlya Biryukov       // we assume relational ops operate on bools.
4444974d75dSIlya Biryukov       c && ^c; c || ^c;
4454974d75dSIlya Biryukov     }
4460250e29eSDavid Green   )cpp";
44769e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
4484974d75dSIlya Biryukov 
44969e181d4SIlya Biryukov   Code = R"cpp(
4504974d75dSIlya Biryukov     class Cls {};
4514974d75dSIlya Biryukov     void test(Cls c) {
4524974d75dSIlya Biryukov       // we make no assumptions about the following operators, since they are
4534974d75dSIlya Biryukov       // often overloaded with a non-standard meaning.
4544974d75dSIlya Biryukov       c << ^c; c >> ^c; c | ^c; c & ^c;
4554974d75dSIlya Biryukov       c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;
4564974d75dSIlya Biryukov     }
4570250e29eSDavid Green   )cpp";
45869e181d4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
4594974d75dSIlya Biryukov }
4604974d75dSIlya Biryukov 
TEST(PreferredTypeTest,Members)4614f9543b4SIlya Biryukov TEST(PreferredTypeTest, Members) {
4624f9543b4SIlya Biryukov   StringRef Code = R"cpp(
4634f9543b4SIlya Biryukov     struct vector {
4644f9543b4SIlya Biryukov       int *begin();
4654f9543b4SIlya Biryukov       vector clone();
4664f9543b4SIlya Biryukov     };
4674f9543b4SIlya Biryukov 
4684f9543b4SIlya Biryukov     void test(int *a) {
4694f9543b4SIlya Biryukov       a = ^vector().^clone().^begin();
4704f9543b4SIlya Biryukov     }
4714f9543b4SIlya Biryukov   )cpp";
4724f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
4734f9543b4SIlya Biryukov }
4744f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,Conditions)4754f9543b4SIlya Biryukov TEST(PreferredTypeTest, Conditions) {
4764f9543b4SIlya Biryukov   StringRef Code = R"cpp(
4774f9543b4SIlya Biryukov     struct vector {
4784f9543b4SIlya Biryukov       bool empty();
4794f9543b4SIlya Biryukov     };
4804f9543b4SIlya Biryukov 
4814f9543b4SIlya Biryukov     void test() {
4824f9543b4SIlya Biryukov       if (^vector().^empty()) {}
4834f9543b4SIlya Biryukov       while (^vector().^empty()) {}
4844f9543b4SIlya Biryukov       for (; ^vector().^empty();) {}
4854f9543b4SIlya Biryukov     }
4864f9543b4SIlya Biryukov   )cpp";
4874f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
4884f9543b4SIlya Biryukov }
4894f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,InitAndAssignment)4904f9543b4SIlya Biryukov TEST(PreferredTypeTest, InitAndAssignment) {
4914f9543b4SIlya Biryukov   StringRef Code = R"cpp(
4924f9543b4SIlya Biryukov     struct vector {
4934f9543b4SIlya Biryukov       int* begin();
4944f9543b4SIlya Biryukov     };
4954f9543b4SIlya Biryukov 
4964f9543b4SIlya Biryukov     void test() {
4974f9543b4SIlya Biryukov       const int* x = ^vector().^begin();
4984f9543b4SIlya Biryukov       x = ^vector().^begin();
4994f9543b4SIlya Biryukov 
5004f9543b4SIlya Biryukov       if (const int* y = ^vector().^begin()) {}
5014f9543b4SIlya Biryukov     }
5024f9543b4SIlya Biryukov   )cpp";
5034f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
5044f9543b4SIlya Biryukov }
5054f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,UnaryExprs)5064f9543b4SIlya Biryukov TEST(PreferredTypeTest, UnaryExprs) {
5074f9543b4SIlya Biryukov   StringRef Code = R"cpp(
5084f9543b4SIlya Biryukov     void test(long long a) {
5094f9543b4SIlya Biryukov       a = +^a;
5104f9543b4SIlya Biryukov       a = -^a
5114f9543b4SIlya Biryukov       a = ++^a;
5124f9543b4SIlya Biryukov       a = --^a;
5134f9543b4SIlya Biryukov     }
5144f9543b4SIlya Biryukov   )cpp";
5154f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
5164f9543b4SIlya Biryukov 
5174f9543b4SIlya Biryukov   Code = R"cpp(
5184f9543b4SIlya Biryukov     void test(int a, int *ptr) {
5194f9543b4SIlya Biryukov       !^a;
5204f9543b4SIlya Biryukov       !^ptr;
5214f9543b4SIlya Biryukov       !!!^a;
5224f9543b4SIlya Biryukov 
5234f9543b4SIlya Biryukov       a = !^a;
5244f9543b4SIlya Biryukov       a = !^ptr;
5254f9543b4SIlya Biryukov       a = !!!^a;
5264f9543b4SIlya Biryukov     }
5274f9543b4SIlya Biryukov   )cpp";
5284f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
5294f9543b4SIlya Biryukov 
5304f9543b4SIlya Biryukov   Code = R"cpp(
5314f9543b4SIlya Biryukov     void test(int a) {
5324f9543b4SIlya Biryukov       const int* x = &^a;
5334f9543b4SIlya Biryukov     }
5344f9543b4SIlya Biryukov   )cpp";
5354f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int"));
5364f9543b4SIlya Biryukov 
5374f9543b4SIlya Biryukov   Code = R"cpp(
5384f9543b4SIlya Biryukov     void test(int *a) {
5394f9543b4SIlya Biryukov       int x = *^a;
5404f9543b4SIlya Biryukov       int &r = *^a;
5414f9543b4SIlya Biryukov     }
5424f9543b4SIlya Biryukov   )cpp";
5434f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
5444f9543b4SIlya Biryukov 
5454f9543b4SIlya Biryukov   Code = R"cpp(
5464f9543b4SIlya Biryukov     void test(int a) {
5474f9543b4SIlya Biryukov       *^a;
5484f9543b4SIlya Biryukov       &^a;
5494f9543b4SIlya Biryukov     }
5504f9543b4SIlya Biryukov 
5514f9543b4SIlya Biryukov   )cpp";
5524f9543b4SIlya Biryukov }
5534f9543b4SIlya Biryukov 
TEST(PreferredTypeTest,ParenExpr)5544f9543b4SIlya Biryukov TEST(PreferredTypeTest, ParenExpr) {
5554f9543b4SIlya Biryukov   StringRef Code = R"cpp(
5564f9543b4SIlya Biryukov     const int *i = ^(^(^(^10)));
5574f9543b4SIlya Biryukov   )cpp";
5584f9543b4SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
5594f9543b4SIlya Biryukov }
560ff2a9975SIlya Biryukov 
TEST(PreferredTypeTest,FunctionArguments)561ff2a9975SIlya Biryukov TEST(PreferredTypeTest, FunctionArguments) {
562ff2a9975SIlya Biryukov   StringRef Code = R"cpp(
563ff2a9975SIlya Biryukov     void foo(const int*);
564ff2a9975SIlya Biryukov 
565ff2a9975SIlya Biryukov     void bar(const int*);
566ff2a9975SIlya Biryukov     void bar(const int*, int b);
567ff2a9975SIlya Biryukov 
568ff2a9975SIlya Biryukov     struct vector {
569ff2a9975SIlya Biryukov       const int *data();
570ff2a9975SIlya Biryukov     };
571ff2a9975SIlya Biryukov     void test() {
572ff2a9975SIlya Biryukov       foo(^(^(^(^vec^tor^().^da^ta^()))));
573ff2a9975SIlya Biryukov       bar(^(^(^(^vec^tor^().^da^ta^()))));
574ff2a9975SIlya Biryukov     }
575ff2a9975SIlya Biryukov   )cpp";
576ff2a9975SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
577ff2a9975SIlya Biryukov 
578ff2a9975SIlya Biryukov   Code = R"cpp(
579ff2a9975SIlya Biryukov     void bar(int, volatile double *);
580ff2a9975SIlya Biryukov     void bar(int, volatile double *, int, int);
581ff2a9975SIlya Biryukov 
582ff2a9975SIlya Biryukov     struct vector {
583ff2a9975SIlya Biryukov       double *data();
584ff2a9975SIlya Biryukov     };
585ff2a9975SIlya Biryukov 
586ff2a9975SIlya Biryukov     struct class_members {
587ff2a9975SIlya Biryukov       void bar(int, volatile double *);
588ff2a9975SIlya Biryukov       void bar(int, volatile double *, int, int);
589ff2a9975SIlya Biryukov     };
590ff2a9975SIlya Biryukov     void test() {
591ff2a9975SIlya Biryukov       bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
592ff2a9975SIlya Biryukov       class_members().bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
593ff2a9975SIlya Biryukov     }
594ff2a9975SIlya Biryukov   )cpp";
595ff2a9975SIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("volatile double *"));
596b1296faeSIlya Biryukov 
597b1296faeSIlya Biryukov   Code = R"cpp(
598b1296faeSIlya Biryukov     namespace ns {
599b1296faeSIlya Biryukov       struct vector {
600b1296faeSIlya Biryukov       };
601b1296faeSIlya Biryukov     }
602b1296faeSIlya Biryukov     void accepts_vector(ns::vector);
603b1296faeSIlya Biryukov 
604b1296faeSIlya Biryukov     void test() {
605b1296faeSIlya Biryukov       accepts_vector(^::^ns::^vector());
606b1296faeSIlya Biryukov     }
607b1296faeSIlya Biryukov   )cpp";
608b1296faeSIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("ns::vector"));
609b1296faeSIlya Biryukov 
610b1296faeSIlya Biryukov   Code = R"cpp(
611b1296faeSIlya Biryukov     template <class T>
612b1296faeSIlya Biryukov     struct vector { using self = vector; };
613b1296faeSIlya Biryukov 
614b1296faeSIlya Biryukov     void accepts_vector(vector<int>);
615b1296faeSIlya Biryukov     int foo(int);
616b1296faeSIlya Biryukov 
617b1296faeSIlya Biryukov     void test() {
618b1296faeSIlya Biryukov       accepts_vector(^::^vector<decltype(foo(1))>::^self);
619b1296faeSIlya Biryukov     }
620b1296faeSIlya Biryukov   )cpp";
621b1296faeSIlya Biryukov   EXPECT_THAT(collectPreferredTypes(Code), Each("vector<int>"));
622ff2a9975SIlya Biryukov }
623f7c8ace4SIlya Biryukov 
TEST(PreferredTypeTest,NoCrashOnInvalidTypes)624f7c8ace4SIlya Biryukov TEST(PreferredTypeTest, NoCrashOnInvalidTypes) {
625f7c8ace4SIlya Biryukov   StringRef Code = R"cpp(
626f7c8ace4SIlya Biryukov     auto x = decltype(&1)(^);
627f7c8ace4SIlya Biryukov     auto y = new decltype(&1)(^);
6286f428e09SHaojian Wu     // GNU decimal type extension is not supported in clang.
6296f428e09SHaojian Wu     auto z = new _Decimal128(^);
630f7431849SKadir Cetinkaya     void foo() { (void)(foo)(^); }
631f7c8ace4SIlya Biryukov   )cpp";
63262dea6e9SHaojian Wu   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
633f7c8ace4SIlya Biryukov }
6346f428e09SHaojian Wu 
63510d95c53SHaojian Wu } // namespace
636