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