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

Fixed a bug I introduced by removing a null-check. I added the null-check back 
in again.


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

https://reviews.llvm.org/D119077

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

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,6 +451,8 @@
   }
 
   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) {
@@ -527,13 +531,135 @@
     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 a HighlightingToken to another SourceLocation. The token at the
+  // given location will be highlighted exactly the same way.
+  void expandToken(HighlightingToken &OldTok, SourceLocation Loc) {
+    if (Loc.isInvalid())
+      return;
+
+    auto &NewTok = H.addToken(Loc, OldTok.Kind);
+    NewTok.Modifiers = OldTok.Modifiers;
+  }
+
+  // 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,
+                                HighlightingToken &OpKeywTok) {
+    if (Loc.isInvalid())
+      return;
+
+    const auto *NextTok = nextToken(Loc);
+    if (!NextTok)
+      return;
+
+    expandToken(OpKeywTok, 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(OpKeywTok, 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(OpKeywTok, NextTok->location()); // `[`.
+      const auto *ParenEndTok = nextToken(NextTok->location());
+      if (ParenEndTok)
+        expandToken(OpKeywTok, 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.isMacroID())
+        return true;
+
+      auto &Kind = *HighlightingKind;
+      auto &OpKeywTok = H.addToken(Loc, Kind);
+
+      // Also highlight the operator token as part of the function name.
+      // E.g. `<<` in `operator<<`.
+      expandOverloadedOperator(Loc, OpKeywTok);
+    }
+
+    return true;
+  }
+
   bool VisitCallExpr(CallExpr *E) {
     // Highlighting parameters passed by non-const reference does not really
     // make sense for literals...
     if (isa<UserDefinedLiteral>(E))
       return true;
 
-    // FIXME ...here it would make sense though.
+    // Already handled by VisitCXXOperatorCallExpr.
     if (isa<CXXOperatorCallExpr>(E))
       return true;
 
@@ -585,6 +711,85 @@
     }
   }
 
+  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)
+      return;
+
+    auto &OpKeywTok = H.addToken(Loc, *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);
+
+    if (!HighlightingKind)
+      return;
+    // Also highlight the operator token as part of the function name.
+    // E.g. `<<` in `operator<<`.
+    expandOverloadedOperator(Loc, OpKeywTok);
+  }
+
   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