diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -754,19 +754,40 @@ // We override this if we want to claim fewer tokens (e.g. there are gaps). void claimTokensFor(const DynTypedNode &N, SelectionTree::Selection &Result) { if (const auto *TL = N.get()) { - // e.g. EltType Foo[OuterSize][InnerSize]; + // We need the DecltypeTypeLoc hack in getSourceRange. + if (TL->getAs()) + return claimRange(getSourceRange(N), Result); + + // E.g. a function which returns a function pointer. + // int (*Fun(OuterType))(InnerType); + // ~~~~~~~~~XXXXXXXXXXX~~~~~~~~~~~~ FunctionProtoTypeLoc + // ~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~ |- PointerTypeLoc: int (*)(InnerType) + // ~~~~XXXXXXXXXXXXXXXXX~~~~~~~~~~~ | `- ParenTypeLoc: int (InnerType) + // ~~~~~~~~~~~~~~~~~~~~~XXXXXXXXXXX | `-FunctionProtoTypeLoc: int (InnerType) + // ~~~~~~~~~ `- ParmVarDecl: OuterType + // The ParenTypeLoc must not claim its local source range (marked as XXX + // above), or it clobbers the outer ParmVarDecl. + if ( auto PTL = TL->getAs()) { + PTL.getLocalSourceRange().dump(SM); + // Only claim the parentheses tokens, other tokens are handled by its + // children or are expected unclaimed. + claimRange(PTL.getLParenLoc(), Result); + claimRange(PTL.getRParenLoc(), Result); + return; + } + + // We use LocalSourceRange as a default claimed range for TypeLocs -- it + // is better than getSourceRange (which returns a range covering itself + // and its children), because we want to claim fewer tokens (multiple + // discontiguous ranges) for some TypeLocs. + // E.g. EltType Foo[OuterSize][InnerSize]; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ArrayTypeLoc (Outer) // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |-ArrayTypeLoc (Inner) // ~~~~~~~ | |-RecordType // ~~~~~~~~~ | `-Expr (InnerSize) // ~~~~~~~~~ `-Expr (OuterSize) // Inner ATL must not claim its whole SourceRange, or it clobbers Outer. - if (TL->getAs()) { - claimRange(TL->getLocalSourceRange(), Result); - return; - } - // FIXME: maybe LocalSourceRange is a better default for TypeLocs. - // It doesn't seem to be usable for FunctionTypeLocs. + return claimRange(TL->getLocalSourceRange(), Result); } claimRange(getSourceRange(N), Result); } diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -231,7 +231,7 @@ R"cpp( [[void (^*S)(int)]] = nullptr; )cpp", - "FunctionProtoTypeLoc", + "PointerTypeLoc", }, { R"cpp( @@ -243,7 +243,7 @@ R"cpp( [[void ^(*S)(int)]] = nullptr; )cpp", - "FunctionProtoTypeLoc", + "ParenTypeLoc", }, { R"cpp( @@ -326,6 +326,8 @@ {"const int x = 1, y = 2; [[i^nt]] array[x][10][y];", "BuiltinTypeLoc"}, {"void func(int x) { int v_array[^[[x]]][10]; }", "DeclRefExpr"}, + {"int (*getFunc([[do^uble]]))(int);", "BuiltinTypeLoc"}, + // FIXME: the AST has no location info for qualifiers. {"const [[a^uto]] x = 42;", "AutoTypeLoc"}, {"[[co^nst auto x = 42]];", "VarDecl"},