hokein created this revision.
hokein added a reviewer: ilya-biryukov.
Herald added subscribers: usaxena95, kadircet, arphaman, jkorous, MaskRay.
Herald added a project: clang.
hokein marked an inline comment as done.
hokein added inline comments.


================
Comment at: clang-tools-extra/clangd/SourceCode.cpp:256
+
 SourceLocation getBeginningOfIdentifier(const Position &Pos,
                                         const SourceManager &SM,
----------------
the function name doesn't match what it does now, considering a new name for 
it, `getBeginningOfIdentifierOrOverloadedOperator` seems too verbose, maybe 
just `getBeginning`?


This will fix some bugs where navigation doesn't work on cases like
`std::cout <^< "hello"`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D67695

Files:
  clang-tools-extra/clangd/SourceCode.cpp
  clang-tools-extra/clangd/unittests/SourceCodeTests.cpp
  clang-tools-extra/clangd/unittests/XRefsTests.cpp

Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -434,6 +434,15 @@
           auto x = m^akeX();
         }
       )cpp",
+
+      R"cpp(
+        struct X {
+          X& [[operator]]++() {}
+        };
+        void foo(X& x) {
+          +^+x;
+        }
+      )cpp",
   };
   for (const char *Test : Tests) {
     Annotations T(Test);
Index: clang-tools-extra/clangd/unittests/SourceCodeTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SourceCodeTests.cpp
+++ clang-tools-extra/clangd/unittests/SourceCodeTests.cpp
@@ -326,6 +326,9 @@
            "int foo(^);",  // non-identifier
            "^int foo();",  // beginning of file (can't back up)
            "int ^f0^0();", // after a digit (lexing at N-1 is wrong)
+           "void f(int abc) { ^a^b^c^++; }", // range of identifier
+           "void f(int abc) { ++^a^b^c^; }", // range of identifier
+           "void f(int abc) { ^+^+abc; }",   // range of operator
            "int ^λλ^λ();", // UTF-8 handled properly when backing up
 
            // identifier in macro arg
Index: clang-tools-extra/clangd/SourceCode.cpp
===================================================================
--- clang-tools-extra/clangd/SourceCode.cpp
+++ clang-tools-extra/clangd/SourceCode.cpp
@@ -237,6 +237,22 @@
   return halfOpenToRange(SM, CharSourceRange::getCharRange(TokLoc, End));
 }
 
+static bool isIdentifierOrOverloadedOperator(const Token &Tok) {
+  switch (Tok.getKind()) {
+  case tok::raw_identifier:
+    return true;
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemOnly)     \
+  case tok::Token:
+#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemOnly)
+#include "clang/Basic/OperatorKinds.def"
+    return true;
+
+  default:
+    break;
+  }
+  return false;
+}
+
 SourceLocation getBeginningOfIdentifier(const Position &Pos,
                                         const SourceManager &SM,
                                         const LangOptions &LangOpts) {
@@ -248,24 +264,39 @@
   }
 
   // GetBeginningOfToken(pos) is almost what we want, but does the wrong thing
-  // if the cursor is at the end of the identifier.
-  // Instead, we lex at GetBeginningOfToken(pos - 1). The cases are:
-  //  1) at the beginning of an identifier, we'll be looking at something
-  //  that isn't an identifier.
-  //  2) at the middle or end of an identifier, we get the identifier.
-  //  3) anywhere outside an identifier, we'll get some non-identifier thing.
+  // if the cursor is at the end of the target token (identifier, overloaded
+  // operators). Instead, we lex at GetBeginningOfToken(pos - 1). The cases are:
+  //  1) at the beginning of a target token, we'll be looking at something
+  //  that isn't a target token.
+  //  2) at the middle or end of a target token, we get the target token.
+  //  3) anywhere outside the target token, we'll get some non-target-token
+  //  thing.
   // We can't actually distinguish cases 1 and 3, but returning the original
   // location is correct for both!
   SourceLocation InputLoc = SM.getComposedLoc(FID, *Offset);
   if (*Offset == 0) // Case 1 or 3.
     return InputLoc;
-  SourceLocation Before = SM.getComposedLoc(FID, *Offset - 1);
 
-  Before = Lexer::GetBeginningOfToken(Before, SM, LangOpts);
   Token Tok;
+  // As we use closed range [start, end] for identifiers, we encounter tricky
+  // cases when identifiers meet with overloaded operators:
+  //   1) ++^foo; => return the start location of foo.
+  //   2) ^foo^++;  => return the start location of foo.
+  //      ~~~~~ range for foo.
+  // so if we see the original location is the beginning of the identifier, we
+  // just return the the original location, otherwise we will return the
+  // beginning loc of "++" in 1).
+  if (InputLoc.isValid() &&
+      InputLoc == Lexer::GetBeginningOfToken(InputLoc, SM, LangOpts) &&
+      !Lexer::getRawToken(InputLoc, Tok, SM, LangOpts, false) &&
+      Tok.is(tok::raw_identifier))
+    return InputLoc; // original location is at the beginning of an identifier.
+
+  SourceLocation Before = SM.getComposedLoc(FID, *Offset - 1);
+  Before = Lexer::GetBeginningOfToken(Before, SM, LangOpts);
   if (Before.isValid() &&
       !Lexer::getRawToken(Before, Tok, SM, LangOpts, false) &&
-      Tok.is(tok::raw_identifier))
+      isIdentifierOrOverloadedOperator(Tok))
     return Before; // Case 2.
   return InputLoc; // Case 1 or 3.
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to