summaryrefslogtreecommitdiff
path: root/clang-tools-extra/unittests/clangd
diff options
context:
space:
mode:
authorIlya Biryukov <ibiryukov@google.com>2018-11-26 15:25:20 +0000
committerIlya Biryukov <ibiryukov@google.com>2018-11-26 15:25:20 +0000
commit70f604d5726ad0aab17166ef0ff710e177f17b1a (patch)
tree4bcb1cf76a71a07f4618586614a4d9884b160885 /clang-tools-extra/unittests/clangd
parent75cc186aa52052986af3bee0d62164778ec02e0e (diff)
[clangd] Initial implementation of expected types
Summary: Provides facilities to model the C++ conversion rules without the AST. The introduced representation can be stored in the index and used to implement type-based ranking improvements for index-based completions. Reviewers: sammccall, ioeric Reviewed By: sammccall Subscribers: malaperle, mgorny, MaskRay, jkorous, arphaman, kadircet, cfe-commits Differential Revision: https://reviews.llvm.org/D52273
Diffstat (limited to 'clang-tools-extra/unittests/clangd')
-rw-r--r--clang-tools-extra/unittests/clangd/CMakeLists.txt1
-rw-r--r--clang-tools-extra/unittests/clangd/ExpectedTypeTest.cpp157
2 files changed, 158 insertions, 0 deletions
diff --git a/clang-tools-extra/unittests/clangd/CMakeLists.txt b/clang-tools-extra/unittests/clangd/CMakeLists.txt
index b6233b07f94..8ac440e444e 100644
--- a/clang-tools-extra/unittests/clangd/CMakeLists.txt
+++ b/clang-tools-extra/unittests/clangd/CMakeLists.txt
@@ -19,6 +19,7 @@ add_extra_unittest(ClangdTests
ContextTests.cpp
DexTests.cpp
DraftStoreTests.cpp
+ ExpectedTypeTest.cpp
FileDistanceTests.cpp
FileIndexTests.cpp
FindSymbolsTests.cpp
diff --git a/clang-tools-extra/unittests/clangd/ExpectedTypeTest.cpp b/clang-tools-extra/unittests/clangd/ExpectedTypeTest.cpp
new file mode 100644
index 00000000000..e739869e437
--- /dev/null
+++ b/clang-tools-extra/unittests/clangd/ExpectedTypeTest.cpp
@@ -0,0 +1,157 @@
+//===-- ExpectedTypeTest.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangdUnit.h"
+#include "ExpectedTypes.h"
+#include "TestTU.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/StringRef.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace clang {
+namespace clangd {
+namespace {
+
+using ::testing::Field;
+using ::testing::Matcher;
+using ::testing::SizeIs;
+using ::testing::UnorderedElementsAreArray;
+
+class ExpectedTypeConversionTest : public ::testing::Test {
+protected:
+ void build(StringRef Code) {
+ assert(!AST && "AST built twice");
+ AST = TestTU::withCode(Code).build();
+ }
+
+ const ValueDecl *decl(StringRef Name) {
+ return &cast<ValueDecl>(findDecl(*AST, Name));
+ }
+
+ QualType typeOf(StringRef Name) {
+ return decl(Name)->getType().getCanonicalType();
+ }
+
+ /// An overload for convenience.
+ Optional<OpaqueType> fromCompletionResult(const ValueDecl *D) {
+ return OpaqueType::fromCompletionResult(
+ ASTCtx(), CodeCompletionResult(D, CCP_Declaration));
+ }
+
+ /// A set of DeclNames whose type match each other computed by
+ /// OpaqueType::fromCompletionResult.
+ using EquivClass = std::set<std::string>;
+
+ Matcher<std::map<std::string, EquivClass>>
+ ClassesAre(ArrayRef<EquivClass> Classes) {
+ using MapEntry = std::map<std::string, EquivClass>::value_type;
+
+ std::vector<Matcher<MapEntry>> Elements;
+ Elements.reserve(Classes.size());
+ for (auto &Cls : Classes)
+ Elements.push_back(Field(&MapEntry::second, Cls));
+ return UnorderedElementsAreArray(Elements);
+ }
+
+ // Groups \p Decls into equivalence classes based on the result of
+ // 'OpaqueType::fromCompletionResult'.
+ std::map<std::string, EquivClass>
+ buildEquivClasses(ArrayRef<StringRef> DeclNames) {
+ std::map<std::string, EquivClass> Classes;
+ for (StringRef Name : DeclNames) {
+ auto Type = OpaqueType::fromType(ASTCtx(), typeOf(Name));
+ Classes[Type->raw()].insert(Name);
+ }
+ return Classes;
+ }
+
+ ASTContext &ASTCtx() { return AST->getASTContext(); }
+
+private:
+ // Set after calling build().
+ Optional<ParsedAST> AST;
+};
+
+TEST_F(ExpectedTypeConversionTest, BasicTypes) {
+ build(R"cpp(
+ // ints.
+ bool b;
+ int i;
+ unsigned int ui;
+ long long ll;
+
+ // floats.
+ float f;
+ double d;
+
+ // pointers
+ int* iptr;
+ bool* bptr;
+
+ // user-defined types.
+ struct X {};
+ X user_type;
+ )cpp");
+
+ EXPECT_THAT(buildEquivClasses({"b", "i", "ui", "ll", "f", "d", "iptr", "bptr",
+ "user_type"}),
+ ClassesAre({{"b"},
+ {"i", "ui", "ll"},
+ {"f", "d"},
+ {"iptr"},
+ {"bptr"},
+ {"user_type"}}));
+}
+
+TEST_F(ExpectedTypeConversionTest, ReferencesDontMatter) {
+ build(R"cpp(
+ int noref;
+ int & ref = noref;
+ const int & const_ref = noref;
+ int && rv_ref = 10;
+ )cpp");
+
+ EXPECT_THAT(buildEquivClasses({"noref", "ref", "const_ref", "rv_ref"}),
+ SizeIs(1));
+}
+
+TEST_F(ExpectedTypeConversionTest, ArraysDecay) {
+ build(R"cpp(
+ int arr[2];
+ int (&arr_ref)[2] = arr;
+ int *ptr;
+ )cpp");
+
+ EXPECT_THAT(buildEquivClasses({"arr", "arr_ref", "ptr"}), SizeIs(1));
+}
+
+TEST_F(ExpectedTypeConversionTest, FunctionReturns) {
+ build(R"cpp(
+ int returns_int();
+ int* returns_ptr();
+
+ int int_;
+ int* int_ptr;
+ )cpp");
+
+ OpaqueType IntTy = *OpaqueType::fromType(ASTCtx(), typeOf("int_"));
+ EXPECT_EQ(fromCompletionResult(decl("returns_int")), IntTy);
+
+ OpaqueType IntPtrTy = *OpaqueType::fromType(ASTCtx(), typeOf("int_ptr"));
+ EXPECT_EQ(fromCompletionResult(decl("returns_ptr")), IntPtrTy);
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang