diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -36,6 +36,7 @@ #include "clang/Index/IndexingAction.h" #include "clang/Index/IndexingOptions.h" #include "clang/Index/USRGeneration.h" +#include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" @@ -592,22 +593,25 @@ // FIXME(nridge): Reduce duplication between this function and declToSym(). static llvm::Optional -declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND) { +declToTypeHierarchyItem(ASTContext &Ctx, const NamedDecl &ND, + const syntax::TokenBuffer &TB) { auto &SM = Ctx.getSourceManager(); - SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager()); - // getFileLoc is a good choice for us, but we also need to make sure - // sourceLocToPosition won't switch files, so we call getSpellingLoc on top of - // that to make sure it does not switch files. - // FIXME: sourceLocToPosition should not switch files! - SourceLocation BeginLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getBeginLoc())); - SourceLocation EndLoc = SM.getSpellingLoc(SM.getFileLoc(ND.getEndLoc())); - if (NameLoc.isInvalid() || BeginLoc.isInvalid() || EndLoc.isInvalid()) - return llvm::None; + auto FilePath = + getCanonicalPath(SM.getFileEntryForID(SM.getFileID(NameLoc)), SM); + auto TUPath = getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM); + if (!FilePath || !TUPath) + return llvm::None; // Not useful without a uri. - Position NameBegin = sourceLocToPosition(SM, NameLoc); - Position NameEnd = sourceLocToPosition( - SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts())); + auto Tokens = TB.spelledForExpanded(TB.expandedTokens(ND.getSourceRange())); + if (!Tokens || Tokens->empty()) + return llvm::None; + const auto *NameTok = + llvm::partition_point(*Tokens, [&SM, &NameLoc](const syntax::Token &T) { + return SM.isBeforeInTranslationUnit(T.location(), NameLoc); + }); + if (!NameTok) + return llvm::None; index::SymbolInfo SymInfo = index::getSymbolInfo(&ND); // FIXME: this is not classifying constructors, destructors and operators @@ -618,20 +622,16 @@ THI.name = printName(Ctx, ND); THI.kind = SK; THI.deprecated = ND.isDeprecated(); - THI.range = - Range{sourceLocToPosition(SM, BeginLoc), sourceLocToPosition(SM, EndLoc)}; - THI.selectionRange = Range{NameBegin, NameEnd}; + THI.range = halfOpenToRange( + SM, syntax::Token::range(SM, Tokens->front(), Tokens->back()) + .toCharRange(SM)); + THI.selectionRange = halfOpenToRange(SM, NameTok->range(SM).toCharRange(SM)); if (!THI.range.contains(THI.selectionRange)) { // 'selectionRange' must be contained in 'range', so in cases where clang // reports unrelated ranges we need to reconcile somehow. THI.range = THI.selectionRange; } - auto FilePath = - getCanonicalPath(SM.getFileEntryForID(SM.getFileID(BeginLoc)), SM); - auto TUPath = getCanonicalPath(SM.getFileEntryForID(SM.getMainFileID()), SM); - if (!FilePath || !TUPath) - return llvm::None; // Not useful without a uri. THI.uri = URIForFile::canonicalize(*FilePath, *TUPath); return THI; @@ -684,7 +684,8 @@ static void fillSuperTypes(const CXXRecordDecl &CXXRD, ASTContext &ASTCtx, std::vector &SuperTypes, - RecursionProtectionSet &RPSet) { + RecursionProtectionSet &RPSet, + const syntax::TokenBuffer &TB) { // typeParents() will replace dependent template specializations // with their class template, so to avoid infinite recursion for // certain types of hierarchies, keep the templates encountered @@ -699,9 +700,9 @@ for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) { if (Optional ParentSym = - declToTypeHierarchyItem(ASTCtx, *ParentDecl)) { + declToTypeHierarchyItem(ASTCtx, *ParentDecl, TB)) { ParentSym->parents.emplace(); - fillSuperTypes(*ParentDecl, ASTCtx, *ParentSym->parents, RPSet); + fillSuperTypes(*ParentDecl, ASTCtx, *ParentSym->parents, RPSet, TB); SuperTypes.emplace_back(std::move(*ParentSym)); } } @@ -795,7 +796,7 @@ return llvm::None; Optional Result = - declToTypeHierarchyItem(AST.getASTContext(), *CXXRD); + declToTypeHierarchyItem(AST.getASTContext(), *CXXRD, AST.getTokens()); if (!Result) return Result; @@ -804,7 +805,8 @@ Result->parents.emplace(); RecursionProtectionSet RPSet; - fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet); + fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet, + AST.getTokens()); } if ((Direction == TypeHierarchyDirection::Children || diff --git a/clang-tools-extra/clangd/test/type-hierarchy.test b/clang-tools-extra/clangd/test/type-hierarchy.test --- a/clang-tools-extra/clangd/test/type-hierarchy.test +++ b/clang-tools-extra/clangd/test/type-hierarchy.test @@ -48,7 +48,7 @@ # CHECK-NEXT: "parents": [], # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { -# CHECK-NEXT: "character": 15, +# CHECK-NEXT: "character": 16, # CHECK-NEXT: "line": 0 # CHECK-NEXT: }, # CHECK-NEXT: "start": { @@ -71,7 +71,7 @@ # CHECK-NEXT: ], # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { -# CHECK-NEXT: "character": 24, +# CHECK-NEXT: "character": 25, # CHECK-NEXT: "line": 1 # CHECK-NEXT: }, # CHECK-NEXT: "start": { @@ -94,7 +94,7 @@ # CHECK-NEXT: ], # CHECK-NEXT: "range": { # CHECK-NEXT: "end": { -# CHECK-NEXT: "character": 24, +# CHECK-NEXT: "character": 25, # CHECK-NEXT: "line": 2 # CHECK-NEXT: }, # CHECK-NEXT: "start": {