xref: /llvm-project/clang-tools-extra/clangd/ExpectedTypes.cpp (revision 5b2772e1fad3fc8b44400b91de4d5bd0724bba75)
12098b86bSDmitri Gribenko //===--- ExpectedTypes.cpp ---------------------------------------*- C++-*-===//
22098b86bSDmitri Gribenko //
32098b86bSDmitri Gribenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42098b86bSDmitri Gribenko // See https://llvm.org/LICENSE.txt for license information.
52098b86bSDmitri Gribenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62098b86bSDmitri Gribenko //
72098b86bSDmitri Gribenko //===----------------------------------------------------------------------===//
82098b86bSDmitri Gribenko 
9d360b298SIlya Biryukov #include "ExpectedTypes.h"
10d360b298SIlya Biryukov #include "clang/AST/ASTContext.h"
11b4a39450SIlya Biryukov #include "clang/AST/DeclTemplate.h"
12d360b298SIlya Biryukov #include "clang/AST/Type.h"
13d360b298SIlya Biryukov #include "clang/Index/USRGeneration.h"
14d360b298SIlya Biryukov #include "clang/Sema/CodeCompleteConsumer.h"
1571f55735SKazu Hirata #include <optional>
16d360b298SIlya Biryukov 
17d360b298SIlya Biryukov namespace clang {
18d360b298SIlya Biryukov namespace clangd {
19d360b298SIlya Biryukov namespace {
20d360b298SIlya Biryukov 
toEquivClass(ASTContext & Ctx,QualType T)21d360b298SIlya Biryukov static const Type *toEquivClass(ASTContext &Ctx, QualType T) {
22d360b298SIlya Biryukov   if (T.isNull() || T->isDependentType())
23d360b298SIlya Biryukov     return nullptr;
24d360b298SIlya Biryukov   // Drop references, we do not handle reference inits properly anyway.
25d360b298SIlya Biryukov   T = T.getCanonicalType().getNonReferenceType();
26d360b298SIlya Biryukov   // Numeric types are the simplest case.
27d360b298SIlya Biryukov   if (T->isBooleanType())
28d360b298SIlya Biryukov     return Ctx.BoolTy.getTypePtr();
29d360b298SIlya Biryukov   if (T->isIntegerType() && !T->isEnumeralType())
30d360b298SIlya Biryukov     return Ctx.IntTy.getTypePtr(); // All integers are equivalent.
31d360b298SIlya Biryukov   if (T->isFloatingType() && !T->isComplexType())
32d360b298SIlya Biryukov     return Ctx.FloatTy.getTypePtr(); // All floats are equivalent.
33d360b298SIlya Biryukov 
34d360b298SIlya Biryukov   // Do some simple transformations.
35d360b298SIlya Biryukov   if (T->isArrayType()) // Decay arrays to pointers.
36d360b298SIlya Biryukov     return Ctx.getPointerType(QualType(T->getArrayElementTypeNoTypeQual(), 0))
37d360b298SIlya Biryukov         .getTypePtr();
38d360b298SIlya Biryukov   // Drop the qualifiers and return the resulting type.
39d360b298SIlya Biryukov   // FIXME: also drop qualifiers from pointer types, e.g. 'const T* => T*'
40d360b298SIlya Biryukov   return T.getTypePtr();
41d360b298SIlya Biryukov }
42d360b298SIlya Biryukov 
typeOfCompletion(const CodeCompletionResult & R)43f71ffd3bSKazu Hirata static std::optional<QualType> typeOfCompletion(const CodeCompletionResult &R) {
44b4a39450SIlya Biryukov   const NamedDecl *D = R.Declaration;
45b4a39450SIlya Biryukov   // Templates do not have a type on their own, look at the templated decl.
46339502ccSIlya Biryukov   if (auto *Template = dyn_cast_or_null<TemplateDecl>(D))
47b4a39450SIlya Biryukov     D = Template->getTemplatedDecl();
48339502ccSIlya Biryukov   auto *VD = dyn_cast_or_null<ValueDecl>(D);
49d360b298SIlya Biryukov   if (!VD)
50059a23c0SKazu Hirata     return std::nullopt; // We handle only variables and functions below.
51d360b298SIlya Biryukov   auto T = VD->getType();
52c514adefSIlya Biryukov   if (T.isNull())
53059a23c0SKazu Hirata     return std::nullopt;
54c0e3c893SChristian Kühnel   if (auto *FuncT = T->getAs<FunctionType>()) {
55d360b298SIlya Biryukov     // Functions are a special case. They are completed as 'foo()' and we want
56d360b298SIlya Biryukov     // to match their return type rather than the function type itself.
57d360b298SIlya Biryukov     // FIXME(ibiryukov): in some cases, we might want to avoid completing `()`
58d360b298SIlya Biryukov     // after the function name, e.g. `std::cout << std::endl`.
59d360b298SIlya Biryukov     return FuncT->getReturnType();
60d360b298SIlya Biryukov   }
61d360b298SIlya Biryukov   return T;
62d360b298SIlya Biryukov }
63d360b298SIlya Biryukov } // namespace
64d360b298SIlya Biryukov 
encode(ASTContext & Ctx,QualType T)65f71ffd3bSKazu Hirata std::optional<OpaqueType> OpaqueType::encode(ASTContext &Ctx, QualType T) {
66d360b298SIlya Biryukov   if (T.isNull())
67059a23c0SKazu Hirata     return std::nullopt;
68d360b298SIlya Biryukov   const Type *C = toEquivClass(Ctx, T);
69d360b298SIlya Biryukov   if (!C)
70059a23c0SKazu Hirata     return std::nullopt;
71f2001aa7SIlya Biryukov   llvm::SmallString<128> Encoded;
72d360b298SIlya Biryukov   if (index::generateUSRForType(QualType(C, 0), Ctx, Encoded))
73059a23c0SKazu Hirata     return std::nullopt;
74*5b2772e1SKazu Hirata   return OpaqueType(std::string(Encoded));
75d360b298SIlya Biryukov }
76d360b298SIlya Biryukov 
OpaqueType(std::string Data)77d360b298SIlya Biryukov OpaqueType::OpaqueType(std::string Data) : Data(std::move(Data)) {}
78d360b298SIlya Biryukov 
fromType(ASTContext & Ctx,QualType Type)79f71ffd3bSKazu Hirata std::optional<OpaqueType> OpaqueType::fromType(ASTContext &Ctx, QualType Type) {
80d360b298SIlya Biryukov   return encode(Ctx, Type);
81d360b298SIlya Biryukov }
82d360b298SIlya Biryukov 
83f71ffd3bSKazu Hirata std::optional<OpaqueType>
fromCompletionResult(ASTContext & Ctx,const CodeCompletionResult & R)84d360b298SIlya Biryukov OpaqueType::fromCompletionResult(ASTContext &Ctx,
85d360b298SIlya Biryukov                                  const CodeCompletionResult &R) {
86d360b298SIlya Biryukov   auto T = typeOfCompletion(R);
87d360b298SIlya Biryukov   if (!T)
88059a23c0SKazu Hirata     return std::nullopt;
89d360b298SIlya Biryukov   return encode(Ctx, *T);
90d360b298SIlya Biryukov }
91d360b298SIlya Biryukov 
92d360b298SIlya Biryukov } // namespace clangd
93d360b298SIlya Biryukov } // namespace clang
94