1010#include " Support/Struct.h"
1111#include " Support/Doxygen.h"
1212#include " llvm/Support/raw_ostream.h"
13+ #include " clang/Sema/HeuristicResolver.h"
1314#include " clang/Lex/Lexer.h"
1415#include " clang/AST/ASTTypeTraits.h"
1516
@@ -39,7 +40,7 @@ static std::vector<HoverItem> get_hover_items(CompilationUnit& unit,
3940
4041 // / TODO: Add other hover items.
4142 if (auto fd = llvm::dyn_cast<clang::FieldDecl>(decl)) {
42- clice::logging::warn (" Got a field decl" );
43+ LOGGING_WARN (" Got a field decl" );
4344 const auto record = fd->getParent ();
4445 add_item (HoverItem::Type, fd->getType ().getAsString ());
4546
@@ -62,12 +63,12 @@ static std::vector<HoverItem> get_hover_items(CompilationUnit& unit,
6263
6364 if (fd->isBitField ()) {
6465 add_item (HoverItem::BitWidth, llvm::Twine (fd->getBitWidthValue ()).str ());
65- clice::logging::warn (" Got bit field, name: {}, bitwidth: {}" ,
66- fd->getName (),
67- fd->getBitWidthValue ());
66+ LOGGING_WARN (" Got bit field, name: {}, bitwidth: {}" ,
67+ fd->getName (),
68+ fd->getBitWidthValue ());
6869 }
6970 } else if (auto vd = llvm::dyn_cast<clang::VarDecl>(decl)) {
70- clice::logging::warn (" Got a var decl" );
71+ LOGGING_WARN (" Got a var decl" );
7172 add_item (HoverItem::Type, vd->getType ().getAsString ());
7273 }
7374
@@ -114,6 +115,208 @@ static std::string get_source_code(CompilationUnit& unit, clang::SourceRange ran
114115 lo)};
115116}
116117
118+ static clang::TemplateTypeParmTypeLoc getContainedAutoParamType (clang::TypeLoc TL) {
119+ if (auto QTL = TL.getAs <clang::QualifiedTypeLoc>())
120+ return getContainedAutoParamType (QTL.getUnqualifiedLoc ());
121+ if (llvm::isa<clang::PointerType, clang::ReferenceType, clang::ParenType>(TL.getTypePtr ()))
122+ return getContainedAutoParamType (TL.getNextTypeLoc ());
123+ if (auto FTL = TL.getAs <clang::FunctionTypeLoc>())
124+ return getContainedAutoParamType (FTL.getReturnLoc ());
125+ if (auto TTPTL = TL.getAs <clang::TemplateTypeParmTypeLoc>()) {
126+ if (TTPTL.getTypePtr ()->getDecl ()->isImplicit ())
127+ return TTPTL;
128+ }
129+ return {};
130+ }
131+
132+ template <typename TemplateDeclTy>
133+ static clang::NamedDecl* getOnlyInstantiationImpl (TemplateDeclTy* TD) {
134+ clang::NamedDecl* Only = nullptr ;
135+ for (auto * Spec: TD->specializations ()) {
136+ if (Spec->getTemplateSpecializationKind () == clang::TSK_ExplicitSpecialization)
137+ continue ;
138+ if (Only != nullptr )
139+ return nullptr ;
140+ Only = Spec;
141+ }
142+ return Only;
143+ }
144+
145+ static clang::NamedDecl* getOnlyInstantiation (clang::NamedDecl* TemplatedDecl) {
146+ if (clang::TemplateDecl* TD = TemplatedDecl->getDescribedTemplate ()) {
147+ if (auto * CTD = llvm::dyn_cast<clang::ClassTemplateDecl>(TD))
148+ return getOnlyInstantiationImpl (CTD);
149+ if (auto * FTD = llvm::dyn_cast<clang::FunctionTemplateDecl>(TD))
150+ return getOnlyInstantiationImpl (FTD);
151+ if (auto * VTD = llvm::dyn_cast<clang::VarTemplateDecl>(TD))
152+ return getOnlyInstantiationImpl (VTD);
153+ }
154+ return nullptr ;
155+ }
156+
157+ // / Computes the deduced type at a given location by visiting the relevant
158+ // / nodes. We use this to display the actual type when hovering over an "auto"
159+ // / keyword or "decltype()" expression.
160+ // / FIXME: This could have been a lot simpler by visiting AutoTypeLocs but it
161+ // / seems that the AutoTypeLocs that can be visited along with their AutoType do
162+ // / not have the deduced type set. Instead, we have to go to the appropriate
163+ // / DeclaratorDecl/FunctionDecl and work our back to the AutoType that does have
164+ // / a deduced type set. The AST should be improved to simplify this scenario.
165+ class DeducedTypeVisitor : public clang ::RecursiveASTVisitor<DeducedTypeVisitor> {
166+ clang::SourceLocation SearchedLocation;
167+ const clang::HeuristicResolver* Resolver;
168+
169+ public:
170+ DeducedTypeVisitor (clang::SourceLocation SearchedLocation,
171+ const clang::HeuristicResolver* Resolver) :
172+ SearchedLocation (SearchedLocation), Resolver(Resolver) {}
173+
174+ // Handle auto initializers:
175+ // - auto i = 1;
176+ // - decltype(auto) i = 1;
177+ // - auto& i = 1;
178+ // - auto* i = &a;
179+ bool VisitDeclaratorDecl (clang::DeclaratorDecl* D) {
180+ if (!D->getTypeSourceInfo () ||
181+ !D->getTypeSourceInfo ()->getTypeLoc ().getContainedAutoTypeLoc () ||
182+ D->getTypeSourceInfo ()->getTypeLoc ().getContainedAutoTypeLoc ().getNameLoc () !=
183+ SearchedLocation)
184+ return true ;
185+
186+ if (auto * AT = D->getType ()->getContainedAutoType ()) {
187+ if (AT->isUndeducedAutoType ()) {
188+ if (const auto * VD = dyn_cast<clang::VarDecl>(D)) {
189+ if (Resolver && VD->hasInit ()) {
190+ // FIXME:
191+ // DeducedType = Resolver->resolveExprToType(VD->getInit());
192+ DeducedType = VD->getType ();
193+ return true ;
194+ }
195+ }
196+ }
197+ DeducedType = AT->desugar ();
198+ }
199+ return true ;
200+ }
201+
202+ // Handle auto return types:
203+ // - auto foo() {}
204+ // - auto& foo() {}
205+ // - auto foo() -> int {}
206+ // - auto foo() -> decltype(1+1) {}
207+ // - operator auto() const { return 10; }
208+ bool VisitFunctionDecl (clang::FunctionDecl* D) {
209+ if (!D->getTypeSourceInfo ())
210+ return true ;
211+ // Loc of auto in return type (c++14).
212+ auto CurLoc = D->getReturnTypeSourceRange ().getBegin ();
213+ // Loc of "auto" in operator auto()
214+ if (CurLoc.isInvalid () && isa<clang::CXXConversionDecl>(D))
215+ CurLoc = D->getTypeSourceInfo ()->getTypeLoc ().getBeginLoc ();
216+ // Loc of "auto" in function with trailing return type (c++11).
217+ if (CurLoc.isInvalid ())
218+ CurLoc = D->getSourceRange ().getBegin ();
219+ if (CurLoc != SearchedLocation)
220+ return true ;
221+
222+ const clang::AutoType* AT = D->getReturnType ()->getContainedAutoType ();
223+ if (AT && !AT->getDeducedType ().isNull ()) {
224+ DeducedType = AT->getDeducedType ();
225+ } else if (auto * DT = dyn_cast<clang::DecltypeType>(D->getReturnType ())) {
226+ // auto in a trailing return type just points to a DecltypeType and
227+ // getContainedAutoType does not unwrap it.
228+ if (!DT->getUnderlyingType ().isNull ())
229+ DeducedType = DT->getUnderlyingType ();
230+ } else if (!D->getReturnType ().isNull ()) {
231+ DeducedType = D->getReturnType ();
232+ }
233+ return true ;
234+ }
235+
236+ // Handle non-auto decltype, e.g.:
237+ // - auto foo() -> decltype(expr) {}
238+ // - decltype(expr);
239+ bool VisitDecltypeTypeLoc (clang::DecltypeTypeLoc TL) {
240+ if (TL.getBeginLoc () != SearchedLocation)
241+ return true ;
242+
243+ // A DecltypeType's underlying type can be another DecltypeType! E.g.
244+ // int I = 0;
245+ // decltype(I) J = I;
246+ // decltype(J) K = J;
247+ const clang::DecltypeType* DT = dyn_cast<clang::DecltypeType>(TL.getTypePtr ());
248+ while (DT && !DT->getUnderlyingType ().isNull ()) {
249+ DeducedType = DT->getUnderlyingType ();
250+ DT = dyn_cast<clang::DecltypeType>(DeducedType.getTypePtr ());
251+ }
252+ return true ;
253+ }
254+
255+ // Handle functions/lambdas with `auto` typed parameters.
256+ // We deduce the type if there's exactly one instantiation visible.
257+ bool VisitParmVarDecl (clang::ParmVarDecl* PVD) {
258+ if (!PVD->getType ()->isDependentType ())
259+ return true ;
260+ // 'auto' here does not name an AutoType, but an implicit template param.
261+ clang::TemplateTypeParmTypeLoc Auto =
262+ getContainedAutoParamType (PVD->getTypeSourceInfo ()->getTypeLoc ());
263+ if (Auto.isNull () || Auto.getNameLoc () != SearchedLocation)
264+ return true ;
265+
266+ // We expect the TTP to be attached to this function template.
267+ // Find the template and the param index.
268+ auto * Templated = llvm::dyn_cast<clang::FunctionDecl>(PVD->getDeclContext ());
269+ if (!Templated)
270+ return true ;
271+ auto * FTD = Templated->getDescribedFunctionTemplate ();
272+ if (!FTD)
273+ return true ;
274+ int ParamIndex = paramIndex (*FTD, *Auto.getDecl ());
275+ if (ParamIndex < 0 ) {
276+ assert (false && " auto TTP is not from enclosing function?" );
277+ return true ;
278+ }
279+
280+ // Now find the instantiation and the deduced template type arg.
281+ auto * Instantiation =
282+ llvm::dyn_cast_or_null<clang::FunctionDecl>(getOnlyInstantiation (Templated));
283+ if (!Instantiation)
284+ return true ;
285+ const auto * Args = Instantiation->getTemplateSpecializationArgs ();
286+ if (Args->size () != FTD->getTemplateParameters ()->size ())
287+ return true ; // no weird variadic stuff
288+ DeducedType = Args->get (ParamIndex).getAsType ();
289+ return true ;
290+ }
291+
292+ static int paramIndex (const clang::TemplateDecl& TD, clang::NamedDecl& Param) {
293+ unsigned I = 0 ;
294+ for (auto * ND: *TD.getTemplateParameters ()) {
295+ if (&Param == ND)
296+ return I;
297+ ++I;
298+ }
299+ return -1 ;
300+ }
301+
302+ clang::QualType DeducedType;
303+ };
304+
305+ // FIXME: Do as clangd did(?) a more simple way?
306+ static std::optional<clang::QualType> getDeducedType (clang::ASTContext& ASTCtx,
307+ const clang::HeuristicResolver* Resolver,
308+ clang::SourceLocation Loc) {
309+ if (!Loc.isValid ()) {
310+ return {};
311+ }
312+ DeducedTypeVisitor V (Loc, Resolver);
313+ V.TraverseAST (ASTCtx);
314+ if (V.DeducedType .isNull ()) {
315+ return std::nullopt ;
316+ }
317+ return V.DeducedType ;
318+ }
319+
117320// TODO: How does clangd put together decl, name, scope and sometimes initialized value?
118321// ```
119322// // scope
@@ -140,22 +343,19 @@ static std::optional<Hover> hover(CompilationUnit& unit,
140343}
141344
142345static std::optional<Hover> hover (CompilationUnit& unit,
143- const clang::TypeLoc* typeloc ,
346+ const clang::QualType& ty ,
144347 const config::HoverOptions& opt) {
145348 // TODO: Hover for type
146- clice::logging::warn (" Hit a typeloc" );
147- typeloc->dump (llvm::errs (), unit.context ());
148- auto ty = typeloc->getType ();
149- // FIXME: AutoTypeLoc / DecltypeTypeLoc
349+ // TODO: Add source code
150350 return Hover{.kind = SymbolKind::Type, .name = ty.getAsString ()};
151351}
152352
153353static std::optional<Hover> hover (CompilationUnit& unit,
154354 const SelectionTree::Node* node,
155355 const config::HoverOptions& opt) {
156356 using namespace clang ;
357+ auto wanted_node = node;
157358 auto Kind = node->data .getNodeKind ();
158- clice::logging::warn (" Node kind is: {}" , Kind.asStringRef ());
159359
160360#define kind_flag_def (Ty ) static constexpr auto Flag##Ty = ASTNodeKind::getFromNodeKind<Ty>()
161361 kind_flag_def (QualType);
@@ -174,42 +374,42 @@ static std::optional<Hover> hover(CompilationUnit& unit,
174374 kind_flag_def (Attr);
175375 kind_flag_def (ObjCProtocolLoc);
176376
177- #define is_in_range (LHS, RHS ) \
178- (!((Kind < Flag##LHS) && (Kind.isSame (Flag##LHS))) && (Kind < Flag##RHS))
179-
180377#define is (flag ) (Kind.isSame(Flag##flag))
181378
379+ #define is_in_range (LHS, RHS ) (!((Kind < Flag##LHS) && is(LHS)) && (Kind < Flag##RHS))
380+
381+ // auto and decltype is specially processed
382+ if (is (AutoTypeLoc) || is (DecltypeTypeLoc)) {
383+ auto resolver = HeuristicResolver (unit.context ());
384+ if (auto ty = getDeducedType (unit.context (), &resolver, node->source_range ().getBegin ())) {
385+ return hover (unit, *ty, opt);
386+ } else {
387+ LOGGING_WARN (" Cannot get deduced type" );
388+ }
389+ }
390+
182391 if (is (NestedNameSpecifierLoc)) {
183- clice::logging::warn (" Hit a `NestedNameSpecifierLoc`" );
392+ LOGGING_WARN (" Hit a `NestedNameSpecifierLoc`" );
184393 } else if (is_in_range (QualType, TypeLoc)) {
185394 // Typeloc
186- clice::logging::warn (" Hit a `TypeLoc`" );
187- // auto and decltype is specially processed
188- if (is (AutoTypeLoc)) {
189- clice::logging::warn (" Hit a `AutoTypeLoc`" );
190- return std::nullopt ;
191- }
192- if (is (DecltypeTypeLoc)) {
193- clice::logging::warn (" Hit a `DecltypeTypeLoc`" );
194- return std::nullopt ;
195- }
395+ LOGGING_WARN (" Hit a `TypeLoc`" );
196396 if (auto typeloc = node->get <clang::TypeLoc>()) {
197- return hover (unit, typeloc, opt);
397+ return hover (unit, typeloc-> getType () , opt);
198398 }
199399 } else if (is_in_range (Decl, Stmt)) {
200400 // Decl
201- clice::logging::warn (" Hit a `Decl`" );
401+ LOGGING_WARN (" Hit a `Decl`" );
202402 if (auto decl = node->get <clang::NamedDecl>()) {
203403 return hover (unit, decl, opt);
204404 } else {
205- clice::logging::warn (" Not intersted" );
405+ LOGGING_WARN (" Not intersted" );
206406 }
207407 } else if (is_in_range (Attr, ObjCProtocolLoc)) {
208- clice::logging::warn (" Hit an `Attr`" );
408+ LOGGING_WARN (" Hit an `Attr`" );
209409 // TODO: Attr
210410 } else {
211411 // Not interested
212- clice::logging::warn (" Not interested" );
412+ LOGGING_WARN (" Not interested" );
213413 }
214414
215415#undef is
@@ -266,10 +466,9 @@ std::optional<Hover> hover(CompilationUnit& unit,
266466 }
267467 }
268468
269- // clice::logging::warn("Hit a macro");
270469 auto tokens_under_cursor = unit.spelled_tokens_touch (*loc);
271470 if (tokens_under_cursor.empty ()) {
272- clice::logging::warn (" Cannot detect tokens" );
471+ LOGGING_WARN (" Cannot detect tokens" );
273472 return std::nullopt ;
274473 }
275474 auto hl_range = tokens_under_cursor.back ().range (sm).toCharRange (sm).getAsRange ();
@@ -314,13 +513,14 @@ std::optional<Hover> hover(CompilationUnit& unit,
314513
315514 auto tree = SelectionTree::create_right (unit, {offset, offset});
316515 if (auto node = tree.common_ancestor ()) {
516+ LOGGING_WARN (" Got node: {}" , node->kind ());
317517 if (auto info = hover (unit, node, opt)) {
318518 info->hl_range = to_proto_range (sm, hl_range);
319519 return info;
320520 }
321521 return std::nullopt ;
322522 } else {
323- clice::logging::warn (" Not an ast node" );
523+ LOGGING_WARN (" Not an ast node" );
324524 }
325525
326526 return std::nullopt ;
0 commit comments