1 //===--- SemanticSelection.cpp -----------------------------------*- C++-*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 #include "SemanticSelection.h"
9 #include "ParsedAST.h"
10 #include "Protocol.h"
11 #include "Selection.h"
12 #include "SourceCode.h"
13 #include "clang/AST/DeclBase.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "llvm/Support/Error.h"
16 
17 namespace clang {
18 namespace clangd {
19 namespace {
20 // Adds Range \p R to the Result if it is distinct from the last added Range.
21 // Assumes that only consecutive ranges can coincide.
addIfDistinct(const Range & R,std::vector<Range> & Result)22 void addIfDistinct(const Range &R, std::vector<Range> &Result) {
23   if (Result.empty() || Result.back() != R) {
24     Result.push_back(R);
25   }
26 }
27 } // namespace
28 
getSemanticRanges(ParsedAST & AST,Position Pos)29 llvm::Expected<std::vector<Range>> getSemanticRanges(ParsedAST &AST,
30                                                      Position Pos) {
31   std::vector<Range> Result;
32   const auto &SM = AST.getSourceManager();
33   const auto &LangOpts = AST.getLangOpts();
34 
35   auto FID = SM.getMainFileID();
36   auto Offset = positionToOffset(SM.getBufferData(FID), Pos);
37   if (!Offset) {
38     return Offset.takeError();
39   }
40 
41   // Get node under the cursor.
42   SelectionTree ST(AST.getASTContext(), AST.getTokens(), *Offset);
43   for (const auto *Node = ST.commonAncestor(); Node != nullptr;
44        Node = Node->Parent) {
45     if (const Decl *D = Node->ASTNode.get<Decl>()) {
46       if (llvm::isa<TranslationUnitDecl>(D)) {
47         break;
48       }
49     }
50 
51     auto SR = toHalfOpenFileRange(SM, LangOpts, Node->ASTNode.getSourceRange());
52     if (!SR.hasValue() || SM.getFileID(SR->getBegin()) != SM.getMainFileID()) {
53       continue;
54     }
55     Range R;
56     R.start = sourceLocToPosition(SM, SR->getBegin());
57     R.end = sourceLocToPosition(SM, SR->getEnd());
58     addIfDistinct(R, Result);
59   }
60   return Result;
61 }
62 
63 } // namespace clangd
64 } // namespace clang
65