iannisdezwart updated this revision to Diff 406452.
iannisdezwart added a comment.

Fixed formatting & reverted a deleted FIXME comment.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119077/new/

https://reviews.llvm.org/D119077

Files:
  clang-tools-extra/clangd/SemanticHighlighting.cpp
  clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Index: clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -109,7 +109,7 @@
         $Class[[AS]]     $LocalVariable_decl[[AA]];
         $Primitive_deduced_defaultLibrary[[auto]] $LocalVariable_decl[[L]] = $LocalVariable[[AA]].$Field[[SomeMember]] + $Parameter[[A]];
         auto $LocalVariable_decl[[FN]] = [ $LocalVariable[[AA]]](int $Parameter_decl[[A]]) -> void {};
-        $LocalVariable[[FN]](12312);
+        $LocalVariable[[FN]]$Method_readonly[[(]]12312$Method_readonly[[)]];
       }
     )cpp",
       R"cpp(
@@ -138,7 +138,7 @@
       struct $Class_decl[[B]] {
         $Class_decl[[B]]();
         ~$Class[[B]](); // FIXME: inconsistent with constructor
-        void operator<<($Class[[B]]);
+        void $Method_decl[[operator<<]]($Class[[B]]);
         $Class[[AAA]] $Field_decl[[AA]];
       };
       $Class[[B]]::$Class_decl[[B]]() {}
@@ -289,10 +289,10 @@
       struct $Class_decl[[B]] {};
       struct $Class_decl[[A]] {
         $Class[[B]] $Field_decl[[BB]];
-        $Class[[A]] &operator=($Class[[A]] &&$Parameter_decl[[O]]);
+        $Class[[A]] &$Method_decl[[operator=]]($Class[[A]] &&$Parameter_decl[[O]]);
       };
 
-      $Class[[A]] &$Class[[A]]::operator=($Class[[A]] &&$Parameter_decl[[O]]) = default;
+      $Class[[A]] &$Class[[A]]::$Method_decl[[operator=]]($Class[[A]] &&$Parameter_decl[[O]]) = default;
     )cpp",
       R"cpp(
       enum $Enum_decl[[En]] {
@@ -777,7 +777,7 @@
         void $Function_decl[[foo]]() {
           int $LocalVariable_decl[[a]], $LocalVariable_decl[[b]];
           [ $LocalVariable_decl[[c]] = $LocalVariable[[a]],
-            $LocalVariable_decl[[d]]($LocalVariable[[b]]) ]() {}();
+            $LocalVariable_decl[[d]]($LocalVariable[[b]]) ]() {}$Method_readonly[[(]]$Method_readonly[[)]];
         }
       )cpp",
       // Enum base specifier
@@ -790,6 +790,34 @@
         typedef int $Primitive_decl[[MyTypedef]];
         enum $Enum_decl[[MyEnum]] : $Primitive[[MyTypedef]] {};
       )cpp",
+      // Overloaded operators
+      R"cpp(
+        struct $Class_decl[[Foo]] {
+          bool $Method_decl[[operator()]]() { return true; }
+          void $Method_decl[[operator<<]](int $Parameter_decl[[K]]) {}
+          operator bool() {} // FIXME: consider how this should be highlighted.
+        };
+
+        namespace $Namespace_decl[[namesp]] {
+          void $Function_decl[[operator--]]($Class[[Foo]] $Parameter_decl[[F]])
+          {}
+        };
+
+        auto $Variable_decl[[a]] =
+          &$Namespace[[namesp]]::$Function[[operator--]];
+
+        void $Function_decl[[operator++]]($Class[[Foo]] &$Parameter_decl[[F]])
+        {}
+
+        int $Function_decl[[main]]() {
+          $Class[[Foo]] $LocalVariable_decl[[foo]];
+          $LocalVariable[[foo]].$Method[[operator()]]();
+          $LocalVariable[[foo]].$Method[[operator<<]](1);
+
+          $Function[[operator++]]($LocalVariable_usedAsMutableReference[[foo]]);
+          $Function[[operator delete[]]]($Function[[operator new[]]](1));
+        }
+      )cpp",
   };
   for (const auto &TestCase : TestCases)
     // Mask off scope modifiers to keep the tests manageable.
Index: clang-tools-extra/clangd/SemanticHighlighting.cpp
===================================================================
--- clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclarationName.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
@@ -26,6 +27,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TokenKinds.h"
 #include "clang/Tooling/Syntax/Tokens.h"
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
@@ -449,8 +451,9 @@
   }
 
   const HeuristicResolver *getResolver() const { return Resolver; }
+  const SourceManager &getSourceMgr() const { return SourceMgr; }
+  const syntax::TokenBuffer &getTB() const { return TB; }
 
-private:
   llvm::Optional<Range> getRangeForSourceLocation(SourceLocation Loc) {
     Loc = getHighlightableSpellingToken(Loc, SourceMgr);
     if (Loc.isInvalid())
@@ -463,6 +466,7 @@
                            Tok->range(SourceMgr).toCharRange(SourceMgr));
   }
 
+private:
   const syntax::TokenBuffer &TB;
   const SourceManager &SourceMgr;
   const LangOptions &LangOpts;
@@ -527,6 +531,124 @@
     return true;
   }
 
+  // Returns the token immediately after a given location.
+  // FIXME: Is this really the best way to do this?
+  const syntax::Token *nextToken(SourceLocation Loc) {
+    if (Loc.isInvalid())
+      return nullptr;
+
+    return llvm::partition_point(
+        H.getTB().spelledTokens(H.getSourceMgr().getFileID(Loc)),
+        [&](const syntax::Token &T) { return T.location() <= Loc; });
+  }
+
+  // Expands the range for a HighlightingToken to another SourceLocation.
+  void expandToken(Range &Range, SourceLocation Loc) {
+    if (Loc.isInvalid())
+      return;
+    Range.end = H.getRangeForSourceLocation(Loc)->end;
+  }
+
+  // For an overloaded operator `operator<<(...)`, we want to the highlighting
+  // to also include the `<<` part. If we don't do this, only the `operator`
+  // part will be correctly highlighted.
+  void expandOverloadedOperator(SourceLocation Loc, Range &OpRange) {
+    const auto *NextTok = nextToken(Loc);
+    if (!NextTok)
+      return;
+
+    expandToken(OpRange, NextTok->location());
+
+    // If this operator is `[` or `(`, we also want to highlight the matching
+    // `]` or `)`.
+    if (NextTok->kind() == tok::l_paren || NextTok->kind() == tok::l_square) {
+      const auto *ParenEndTok = nextToken(NextTok->location());
+      if (ParenEndTok)
+        expandToken(OpRange, ParenEndTok->location()); // `]` or `)`.
+    }
+
+    // If this operator is `new[]` or `delete[]`,
+    // we also want to highlight the `[]` part.
+    else if (NextTok->kind() == tok::kw_new ||
+             NextTok->kind() == tok::kw_delete) {
+      NextTok = nextToken(NextTok->location());
+      if (!NextTok || NextTok->kind() != tok::l_square)
+        return;
+      expandToken(OpRange, NextTok->location()); // `[`.
+      const auto *ParenEndTok = nextToken(NextTok->location());
+      if (ParenEndTok)
+        expandToken(OpRange, ParenEndTok->location()); // `]`.
+    }
+  }
+
+  void highlightOperatorCallExpr(SourceLocation Loc, FunctionDecl *FD) {
+    auto HighlightingKind = kindForDecl(FD, H.getResolver());
+    if (!HighlightingKind)
+      return;
+
+    auto &Tok = H.addToken(Loc, *HighlightingKind);
+    if (auto Mod = scopeModifier(FD))
+      Tok.addModifier(*Mod);
+    if (isConst(FD))
+      Tok.addModifier(HighlightingModifier::Readonly);
+    if (isStatic(FD))
+      Tok.addModifier(HighlightingModifier::Static);
+    if (isAbstract(FD))
+      Tok.addModifier(HighlightingModifier::Abstract);
+    if (isVirtual(FD))
+      Tok.addModifier(HighlightingModifier::Virtual);
+    if (isDependent(FD))
+      Tok.addModifier(HighlightingModifier::DependentName);
+    if (isDefaultLibrary(FD))
+      Tok.addModifier(HighlightingModifier::DefaultLibrary);
+    if (FD->isDeprecated())
+      Tok.addModifier(HighlightingModifier::Deprecated);
+  }
+
+  // Highlight called overloaded operators.
+  // E.g. `<<` in `std::cout << "foo"`.
+  bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *O) {
+    // Highlight calls to overloaded operators as function-like types.
+    auto *FD = dyn_cast_or_null<FunctionDecl>(O->getCalleeDecl());
+    if (!FD)
+      return true;
+
+    auto HighlightingKind = kindForDecl(FD, H.getResolver());
+    if (!HighlightingKind)
+      return true;
+
+    auto Loc = O->getOperatorLoc();
+    if (Loc.isMacroID())
+      return true;
+
+    highlightOperatorCallExpr(Loc, FD);
+    return true;
+  }
+
+  bool VisitFunctionDecl(FunctionDecl *FD) {
+    if (FD->isOverloadedOperator()) {
+      auto HighlightingKind = kindForDecl(FD, H.getResolver());
+      if (!HighlightingKind)
+        return true;
+
+      auto Loc = FD->getLocation();
+      if (Loc.isInvalid() || Loc.isMacroID())
+        return true;
+
+      Range OpRange = *H.getRangeForSourceLocation(Loc);
+
+      // Also highlight the operator token as part of the function name.
+      // E.g. `<<` in `operator<<`.
+      expandOverloadedOperator(Loc, OpRange);
+
+      auto &Kind = *HighlightingKind;
+      auto &OpKeywTok = H.addToken(OpRange, Kind);
+      OpKeywTok.addModifier(HighlightingModifier::Declaration);
+    }
+
+    return true;
+  }
+
   bool VisitCallExpr(CallExpr *E) {
     // Highlighting parameters passed by non-const reference does not really
     // make sense for literals...
@@ -585,6 +707,86 @@
     }
   }
 
+  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+    if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
+      if (FD->isOverloadedOperator()) {
+        auto Loc = DRE->getLocation();
+        if (Loc.isMacroID())
+          return true;
+
+        const auto *Tok = H.getTB().spelledTokenAt(Loc);
+        if (!Tok)
+          return true;
+
+        if (Tok->kind() == tok::kw_operator) {
+          // Highlight the operator token as part of the function name.
+          // E.g. `<<` in `operator<<`.
+          highlightOverloadedOperatorFunctionNotation(FD, Loc);
+        } else if (Tok->kind() == tok::l_square ||
+                   Tok->kind() == tok::l_paren) {
+          // Highlight the `[` or `(` token that `VisitCXXOperatorCallExpr`
+          // did not highlight.
+          highlightOperatorCallExpr(Loc, FD);
+        }
+      }
+    }
+
+    return true;
+  }
+
+  bool VisitMemberExpr(MemberExpr *ME) {
+    if (auto *FD = dyn_cast<FunctionDecl>(ME->getMemberDecl())) {
+      if (FD->isOverloadedOperator()) {
+        auto Loc = ME->getMemberLoc();
+        if (Loc.isMacroID())
+          return true;
+
+        const auto *Tok = H.getTB().spelledTokenAt(Loc);
+        if (Tok && Tok->kind() == tok::kw_operator) {
+          // Highlight the operator token as part of the function name.
+          // E.g. `<<` in `operator<<`.
+          highlightOverloadedOperatorFunctionNotation(FD, Loc);
+        }
+      }
+    }
+
+    return true;
+  }
+
+  // Handle operator calls in function notation such as `operator<<(...)`.
+  void highlightOverloadedOperatorFunctionNotation(FunctionDecl *FD,
+                                                   SourceLocation Loc) {
+    auto HighlightingKind = kindForDecl(FD, H.getResolver());
+    if (!HighlightingKind || Loc.isInvalid())
+      return;
+
+    Range OpRange = *H.getRangeForSourceLocation(Loc);
+
+    if (!HighlightingKind || Loc.isInvalid())
+      return;
+    // Also highlight the operator token as part of the function name.
+    // E.g. `<<` in `operator<<`.
+    expandOverloadedOperator(Loc, OpRange);
+
+    auto &OpKeywTok = H.addToken(OpRange, *HighlightingKind);
+    if (auto Mod = scopeModifier(FD))
+      OpKeywTok.addModifier(*Mod);
+    if (isConst(FD))
+      OpKeywTok.addModifier(HighlightingModifier::Readonly);
+    if (isStatic(FD))
+      OpKeywTok.addModifier(HighlightingModifier::Static);
+    if (isAbstract(FD))
+      OpKeywTok.addModifier(HighlightingModifier::Abstract);
+    if (isVirtual(FD))
+      OpKeywTok.addModifier(HighlightingModifier::Virtual);
+    if (isDependent(FD))
+      OpKeywTok.addModifier(HighlightingModifier::DependentName);
+    if (isDefaultLibrary(FD))
+      OpKeywTok.addModifier(HighlightingModifier::DefaultLibrary);
+    if (FD->isDeprecated())
+      OpKeywTok.addModifier(HighlightingModifier::Deprecated);
+  }
+
   bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) {
     if (auto K = kindForType(L.getTypePtr(), H.getResolver())) {
       auto &Tok = H.addToken(L.getBeginLoc(), *K)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to