summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/clang/unittests/Sema/CodeCompleteTest.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
commite5dd70708596ae51455a0ffa086a00c5b29f8583 (patch)
tree5d676f27b570bacf71e786c3b5cff3e6f6679b59 /gnu/llvm/clang/unittests/Sema/CodeCompleteTest.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.tar.xz
wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/clang/unittests/Sema/CodeCompleteTest.cpp')
-rw-r--r--gnu/llvm/clang/unittests/Sema/CodeCompleteTest.cpp492
1 files changed, 492 insertions, 0 deletions
diff --git a/gnu/llvm/clang/unittests/Sema/CodeCompleteTest.cpp b/gnu/llvm/clang/unittests/Sema/CodeCompleteTest.cpp
new file mode 100644
index 00000000000..a9441a679ca
--- /dev/null
+++ b/gnu/llvm/clang/unittests/Sema/CodeCompleteTest.cpp
@@ -0,0 +1,492 @@
+//=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Testing/Support/Annotations.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cstddef>
+#include <string>
+
+namespace {
+
+using namespace clang;
+using namespace clang::tooling;
+using ::testing::Each;
+using ::testing::UnorderedElementsAre;
+
+const char TestCCName[] = "test.cc";
+
+struct CompletionContext {
+ std::vector<std::string> VisitedNamespaces;
+ std::string PreferredType;
+ // String representation of std::ptrdiff_t on a given platform. This is a hack
+ // to properly account for different configurations of clang.
+ std::string PtrDiffType;
+};
+
+class VisitedContextFinder : public CodeCompleteConsumer {
+public:
+ VisitedContextFinder(CompletionContext &ResultCtx)
+ : CodeCompleteConsumer(/*CodeCompleteOpts=*/{}), ResultCtx(ResultCtx),
+ CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
+
+ void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult *Results,
+ unsigned NumResults) override {
+ ResultCtx.VisitedNamespaces =
+ getVisitedNamespace(Context.getVisitedContexts());
+ ResultCtx.PreferredType = Context.getPreferredType().getAsString();
+ ResultCtx.PtrDiffType =
+ S.getASTContext().getPointerDiffType().getAsString();
+ }
+
+ CodeCompletionAllocator &getAllocator() override {
+ return CCTUInfo.getAllocator();
+ }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+private:
+ std::vector<std::string> getVisitedNamespace(
+ CodeCompletionContext::VisitedContextSet VisitedContexts) const {
+ std::vector<std::string> NSNames;
+ for (const auto *Context : VisitedContexts)
+ if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
+ NSNames.push_back(NS->getQualifiedNameAsString());
+ return NSNames;
+ }
+
+ CompletionContext &ResultCtx;
+ CodeCompletionTUInfo CCTUInfo;
+};
+
+class CodeCompleteAction : public SyntaxOnlyAction {
+public:
+ CodeCompleteAction(ParsedSourceLocation P, CompletionContext &ResultCtx)
+ : CompletePosition(std::move(P)), ResultCtx(ResultCtx) {}
+
+ bool BeginInvocation(CompilerInstance &CI) override {
+ CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
+ CI.setCodeCompletionConsumer(new VisitedContextFinder(ResultCtx));
+ return true;
+ }
+
+private:
+ // 1-based code complete position <Line, Col>;
+ ParsedSourceLocation CompletePosition;
+ CompletionContext &ResultCtx;
+};
+
+ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
+ Offset = std::min(Code.size(), Offset);
+ StringRef Before = Code.substr(0, Offset);
+ int Lines = Before.count('\n');
+ size_t PrevNL = Before.rfind('\n');
+ size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
+ return {TestCCName, static_cast<unsigned>(Lines + 1),
+ static_cast<unsigned>(Offset - StartOfLine + 1)};
+}
+
+CompletionContext runCompletion(StringRef Code, size_t Offset) {
+ CompletionContext ResultCtx;
+ clang::tooling::runToolOnCodeWithArgs(
+ std::make_unique<CodeCompleteAction>(offsetToPosition(Code, Offset),
+ ResultCtx),
+ Code, {"-std=c++11"}, TestCCName);
+ return ResultCtx;
+}
+
+CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
+ llvm::Annotations A(AnnotatedCode);
+ return runCompletion(A.code(), A.point());
+}
+
+std::vector<std::string>
+collectPreferredTypes(StringRef AnnotatedCode,
+ std::string *PtrDiffType = nullptr) {
+ llvm::Annotations A(AnnotatedCode);
+ std::vector<std::string> Types;
+ for (size_t Point : A.points()) {
+ auto Results = runCompletion(A.code(), Point);
+ if (PtrDiffType) {
+ assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType);
+ *PtrDiffType = Results.PtrDiffType;
+ }
+ Types.push_back(Results.PreferredType);
+ }
+ return Types;
+}
+
+TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
+ auto VisitedNS = runCodeCompleteOnCode(R"cpp(
+ namespace ns1 {}
+ namespace ns2 {}
+ namespace ns3 {}
+ namespace ns3 { namespace nns3 {} }
+
+ namespace foo {
+ using namespace ns1;
+ namespace ns4 {} // not visited
+ namespace { using namespace ns2; }
+ inline namespace bar { using namespace ns3::nns3; }
+ } // foo
+ namespace ns { foo::^ }
+ )cpp")
+ .VisitedNamespaces;
+ EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
+ "foo::(anonymous)"));
+}
+
+TEST(SemaCodeCompleteTest, VisitedNSForInvalidQualifiedId) {
+ auto VisitedNS = runCodeCompleteOnCode(R"cpp(
+ namespace na {}
+ namespace ns1 {
+ using namespace na;
+ foo::^
+ }
+ )cpp")
+ .VisitedNamespaces;
+ EXPECT_THAT(VisitedNS, UnorderedElementsAre("ns1", "na"));
+}
+
+TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
+ auto VisitedNS = runCodeCompleteOnCode(R"cpp(
+ namespace n1 {
+ namespace n2 {
+ void f(^) {}
+ }
+ }
+ )cpp")
+ .VisitedNamespaces;
+ EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));
+}
+
+TEST(PreferredTypeTest, BinaryExpr) {
+ // Check various operations for arithmetic types.
+ StringRef Code = R"cpp(
+ void test(int x) {
+ x = ^10;
+ x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
+ x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
+ })cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
+
+ Code = R"cpp(
+ void test(float x) {
+ x = ^10;
+ x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
+ x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
+ })cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("float"));
+
+ // Pointer types.
+ Code = R"cpp(
+ void test(int *ptr) {
+ ptr - ^ptr;
+ ptr = ^ptr;
+ })cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
+
+ Code = R"cpp(
+ void test(int *ptr) {
+ ptr + ^10;
+ ptr += ^10;
+ ptr -= ^10;
+ })cpp";
+ {
+ std::string PtrDiff;
+ auto Types = collectPreferredTypes(Code, &PtrDiff);
+ EXPECT_THAT(Types, Each(PtrDiff));
+ }
+
+ // Comparison operators.
+ Code = R"cpp(
+ void test(int i) {
+ i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
+
+ Code = R"cpp(
+ void test(int *ptr) {
+ ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;
+ ptr == ^ptr; ptr != ^ptr;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
+
+ // Relational operations.
+ Code = R"cpp(
+ void test(int i, int *ptr) {
+ i && ^1; i || ^1;
+ ptr && ^1; ptr || ^1;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
+
+ // Bitwise operations.
+ Code = R"cpp(
+ void test(long long ll) {
+ ll | ^1; ll & ^1;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
+
+ Code = R"cpp(
+ enum A {};
+ void test(A a) {
+ a | ^1; a & ^1;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
+
+ Code = R"cpp(
+ enum class A {};
+ void test(A a) {
+ // This is technically illegal with the 'enum class' without overloaded
+ // operators, but we pretend it's fine.
+ a | ^a; a & ^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
+
+ // Binary shifts.
+ Code = R"cpp(
+ void test(int i, long long ll) {
+ i << ^1; ll << ^1;
+ i <<= ^1; i <<= ^1;
+ i >> ^1; ll >> ^1;
+ i >>= ^1; i >>= ^1;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
+
+ // Comma does not provide any useful information.
+ Code = R"cpp(
+ class Cls {};
+ void test(int i, int* ptr, Cls x) {
+ (i, ^i);
+ (ptr, ^ptr);
+ (x, ^x);
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
+
+ // User-defined types do not take operator overloading into account.
+ // However, they provide heuristics for some common cases.
+ Code = R"cpp(
+ class Cls {};
+ void test(Cls c) {
+ // we assume arithmetic and comparions ops take the same type.
+ c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;
+ c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;
+ // same for the assignments.
+ c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("class Cls"));
+
+ Code = R"cpp(
+ class Cls {};
+ void test(Cls c) {
+ // we assume relational ops operate on bools.
+ c && ^c; c || ^c;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
+
+ Code = R"cpp(
+ class Cls {};
+ void test(Cls c) {
+ // we make no assumptions about the following operators, since they are
+ // often overloaded with a non-standard meaning.
+ c << ^c; c >> ^c; c | ^c; c & ^c;
+ c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
+}
+
+TEST(PreferredTypeTest, Members) {
+ StringRef Code = R"cpp(
+ struct vector {
+ int *begin();
+ vector clone();
+ };
+
+ void test(int *a) {
+ a = ^vector().^clone().^begin();
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
+}
+
+TEST(PreferredTypeTest, Conditions) {
+ StringRef Code = R"cpp(
+ struct vector {
+ bool empty();
+ };
+
+ void test() {
+ if (^vector().^empty()) {}
+ while (^vector().^empty()) {}
+ for (; ^vector().^empty();) {}
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
+}
+
+TEST(PreferredTypeTest, InitAndAssignment) {
+ StringRef Code = R"cpp(
+ struct vector {
+ int* begin();
+ };
+
+ void test() {
+ const int* x = ^vector().^begin();
+ x = ^vector().^begin();
+
+ if (const int* y = ^vector().^begin()) {}
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
+}
+
+TEST(PreferredTypeTest, UnaryExprs) {
+ StringRef Code = R"cpp(
+ void test(long long a) {
+ a = +^a;
+ a = -^a
+ a = ++^a;
+ a = --^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
+
+ Code = R"cpp(
+ void test(int a, int *ptr) {
+ !^a;
+ !^ptr;
+ !!!^a;
+
+ a = !^a;
+ a = !^ptr;
+ a = !!!^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
+
+ Code = R"cpp(
+ void test(int a) {
+ const int* x = &^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int"));
+
+ Code = R"cpp(
+ void test(int *a) {
+ int x = *^a;
+ int &r = *^a;
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
+
+ Code = R"cpp(
+ void test(int a) {
+ *^a;
+ &^a;
+ }
+
+ )cpp";
+}
+
+TEST(PreferredTypeTest, ParenExpr) {
+ StringRef Code = R"cpp(
+ const int *i = ^(^(^(^10)));
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
+}
+
+TEST(PreferredTypeTest, FunctionArguments) {
+ StringRef Code = R"cpp(
+ void foo(const int*);
+
+ void bar(const int*);
+ void bar(const int*, int b);
+
+ struct vector {
+ const int *data();
+ };
+ void test() {
+ foo(^(^(^(^vec^tor^().^da^ta^()))));
+ bar(^(^(^(^vec^tor^().^da^ta^()))));
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
+
+ Code = R"cpp(
+ void bar(int, volatile double *);
+ void bar(int, volatile double *, int, int);
+
+ struct vector {
+ double *data();
+ };
+
+ struct class_members {
+ void bar(int, volatile double *);
+ void bar(int, volatile double *, int, int);
+ };
+ void test() {
+ bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
+ class_members().bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("volatile double *"));
+
+ Code = R"cpp(
+ namespace ns {
+ struct vector {
+ };
+ }
+ void accepts_vector(ns::vector);
+
+ void test() {
+ accepts_vector(^::^ns::^vector());
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("ns::vector"));
+
+ Code = R"cpp(
+ template <class T>
+ struct vector { using self = vector; };
+
+ void accepts_vector(vector<int>);
+ int foo(int);
+
+ void test() {
+ accepts_vector(^::^vector<decltype(foo(1))>::^self);
+ }
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("vector<int>"));
+}
+
+TEST(PreferredTypeTest, NoCrashOnInvalidTypes) {
+ StringRef Code = R"cpp(
+ auto x = decltype(&1)(^);
+ auto y = new decltype(&1)(^);
+ )cpp";
+ EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
+}
+} // namespace