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 @@ -511,6 +511,24 @@ bool TraverseTypeLoc(TypeLoc X) { return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); }); } + + // Multi-dimensional arrays are tricky: + // + // int array[Size][10]; + // ~~~ ~~~~~~~~~~ ConstantArrayTypeLoc int[Size][10] + // ~~~ ~~~~ |-ConstantArrayTypeLoc int[10] + // + // We have two nested ConstantArrayTypeLocs, both claim the same token range. + // We want to the SizeExpr in the first ConstantArrayTypeLoc to own the "Size" + // token rather than the second ConstantArrayTypeLoc. + // We override the default ConstantArrayTypeLoc traversal behavior by swaping + // the traversal order of SizeExpr and ElementTypeLoc, which gives a chance + // for the SizeExpr to claim its tokens. + bool TraverseConstantArrayTypeLoc(ConstantArrayTypeLoc X) { + if (!Base::TraverseStmt(X.getSizeExpr())) + return false; + return TraverseTypeLoc(X.getElementLoc()); + } bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &X) { return traverseNode(&X, [&] { return Base::TraverseTemplateArgumentLoc(X); }); 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 @@ -318,6 +318,13 @@ {"[[st^ruct {int x;}]] y;", "CXXRecordDecl"}, {"[[struct {int x;} ^y]];", "VarDecl"}, {"struct {[[int ^x]];} y;", "FieldDecl"}, + + // Tricky case: nested ConstantArrayTypeLocs have the same token range. + {"const int x = 1, y = 2; int array[^[[x]]][10][y];", "DeclRefExpr"}, + {"const int x = 1, y = 2; int array[x][10][^[[y]]];", "DeclRefExpr"}, + {"const int x = 1, y = 2; int array[x][^[[10]]][y];", "IntegerLiteral"}, + {"const int x = 1, y = 2; [[i^nt]] array[x][10][y];", "BuiltinTypeLoc"}, + // FIXME: the AST has no location info for qualifiers. {"const [[a^uto]] x = 42;", "AutoTypeLoc"}, {"[[co^nst auto x = 42]];", "VarDecl"},