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 @@ -8,10 +8,13 @@ #include "Selection.h" #include "ClangdUnit.h" +#include "SourceCode.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "llvm/ADT/STLExtras.h" #include @@ -236,29 +239,29 @@ // Perform hit-testing of a complete Node against the selection. // This runs for every node in the AST, and must be fast in common cases. // This is usually called from pop(), so we can take children into account. + // FIXME: Doesn't select the binary operator node in + // #define FOO(X) X + 1 + // int a, b = [[FOO(a)]]; SelectionTree::Selection claimRange(SourceRange S) { if (!S.isValid()) return SelectionTree::Unselected; - // getTopMacroCallerLoc() allows selection of constructs in macro args. e.g: + // toHalfOpenFileRange() allows selection of constructs in macro args. e.g: // #define LOOP_FOREVER(Body) for(;;) { Body } // void IncrementLots(int &x) { // LOOP_FOREVER( ++x; ) // } // Selecting "++x" or "x" will do the right thing. - auto B = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getBegin())); - auto E = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getEnd())); + auto Range = toHalfOpenFileRange(SM, LangOpts, S); + assert(Range && "We should be able to get the File Range"); + auto B = SM.getDecomposedLoc(Range->getBegin()); + auto E = SM.getDecomposedLoc(Range->getEnd()); // Otherwise, nodes in macro expansions can't be selected. if (B.first != SelFile || E.first != SelFile) return SelectionTree::Unselected; // Cheap test: is there any overlap at all between the selection and range? - // Note that E.second is the *start* of the last token, which is why we - // compare against the "rounded-down" SelBegin. - if (B.second >= SelEnd || E.second < SelBeginTokenStart) + if (B.second >= SelEnd || E.second < SelBegin) return SelectionTree::Unselected; - // We may have hit something, need some more precise checks. - // Adjust [B, E) to be a half-open character range. - E.second += Lexer::MeasureTokenLength(S.getEnd(), SM, LangOpts); auto PreciseBounds = std::make_pair(B.second, E.second); // Trim range using the selection, drop it if empty. B.second = std::max(B.second, SelBegin); 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 @@ -37,15 +37,15 @@ Range nodeRange(const SelectionTree::Node *N, ParsedAST &AST) { if (!N) return Range{}; - SourceManager &SM = AST.getSourceManager(); + const SourceManager &SM = AST.getSourceManager(); + const LangOptions &LangOpts = AST.getASTContext().getLangOpts(); StringRef Buffer = SM.getBufferData(SM.getMainFileID()); - SourceRange SR = N->ASTNode.getSourceRange(); - SR.setBegin(SM.getFileLoc(SR.getBegin())); - SR.setEnd(SM.getFileLoc(SR.getEnd())); - CharSourceRange R = - Lexer::getAsCharRange(SR, SM, AST.getASTContext().getLangOpts()); - return Range{offsetToPosition(Buffer, SM.getFileOffset(R.getBegin())), - offsetToPosition(Buffer, SM.getFileOffset(R.getEnd()))}; + auto FileRange = + toHalfOpenFileRange(SM, LangOpts, N->ASTNode.getSourceRange()); + assert(FileRange && "We should be able to get the File Range"); + return Range{ + offsetToPosition(Buffer, SM.getFileOffset(FileRange->getBegin())), + offsetToPosition(Buffer, SM.getFileOffset(FileRange->getEnd()))}; } std::string nodeKind(const SelectionTree::Node *N) { @@ -144,17 +144,17 @@ R"cpp( void foo(); #define CALL_FUNCTION(X) X() - void bar() [[{ CALL_FUNC^TION(fo^o); }]] + void bar() { [[CALL_FUNC^TION(fo^o)]]; } )cpp", - "CompoundStmt", + "CallExpr", }, { R"cpp( void foo(); #define CALL_FUNCTION(X) X() - void bar() [[{ C^ALL_FUNC^TION(foo); }]] + void bar() { [[C^ALL_FUNC^TION(foo)]]; } )cpp", - "CompoundStmt", + "CallExpr", }, { R"cpp( @@ -308,8 +308,9 @@ R"cpp( template struct unique_ptr {}; - void foo(^$C[[unique_ptr>]]^ a) {} + void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {} )cpp", + R"cpp(int a = [[5 >^> 1]];)cpp", }; for (const char *C : Cases) { Annotations Test(C);