1 //===--- ExpectedTypes.cpp ---------------------------------------*- C++-*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "ExpectedTypes.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/DeclTemplate.h"
12 #include "clang/AST/Type.h"
13 #include "clang/Index/USRGeneration.h"
14 #include "clang/Sema/CodeCompleteConsumer.h"
21 static const Type
*toEquivClass(ASTContext
&Ctx
, QualType T
) {
22 if (T
.isNull() || T
->isDependentType())
24 // Drop references, we do not handle reference inits properly anyway.
25 T
= T
.getCanonicalType().getNonReferenceType();
26 // Numeric types are the simplest case.
27 if (T
->isBooleanType())
28 return Ctx
.BoolTy
.getTypePtr();
29 if (T
->isIntegerType() && !T
->isEnumeralType())
30 return Ctx
.IntTy
.getTypePtr(); // All integers are equivalent.
31 if (T
->isFloatingType() && !T
->isComplexType())
32 return Ctx
.FloatTy
.getTypePtr(); // All floats are equivalent.
34 // Do some simple transformations.
35 if (T
->isArrayType()) // Decay arrays to pointers.
36 return Ctx
.getPointerType(QualType(T
->getArrayElementTypeNoTypeQual(), 0))
38 // Drop the qualifiers and return the resulting type.
39 // FIXME: also drop qualifiers from pointer types, e.g. 'const T* => T*'
40 return T
.getTypePtr();
43 static std::optional
<QualType
> typeOfCompletion(const CodeCompletionResult
&R
) {
44 const NamedDecl
*D
= R
.Declaration
;
45 // Templates do not have a type on their own, look at the templated decl.
46 if (auto *Template
= dyn_cast_or_null
<TemplateDecl
>(D
))
47 D
= Template
->getTemplatedDecl();
48 auto *VD
= dyn_cast_or_null
<ValueDecl
>(D
);
50 return std::nullopt
; // We handle only variables and functions below.
51 auto T
= VD
->getType();
54 if (auto *FuncT
= T
->getAs
<FunctionType
>()) {
55 // Functions are a special case. They are completed as 'foo()' and we want
56 // to match their return type rather than the function type itself.
57 // FIXME(ibiryukov): in some cases, we might want to avoid completing `()`
58 // after the function name, e.g. `std::cout << std::endl`.
59 return FuncT
->getReturnType();
65 std::optional
<OpaqueType
> OpaqueType::encode(ASTContext
&Ctx
, QualType T
) {
68 const Type
*C
= toEquivClass(Ctx
, T
);
71 llvm::SmallString
<128> Encoded
;
72 if (index::generateUSRForType(QualType(C
, 0), Ctx
, Encoded
))
74 return OpaqueType(std::string(Encoded
));
77 OpaqueType::OpaqueType(std::string Data
) : Data(std::move(Data
)) {}
79 std::optional
<OpaqueType
> OpaqueType::fromType(ASTContext
&Ctx
, QualType Type
) {
80 return encode(Ctx
, Type
);
83 std::optional
<OpaqueType
>
84 OpaqueType::fromCompletionResult(ASTContext
&Ctx
,
85 const CodeCompletionResult
&R
) {
86 auto T
= typeOfCompletion(R
);
89 return encode(Ctx
, *T
);