clang-tools  10.0.0git
AnnotateHighlightings.cpp
Go to the documentation of this file.
1 //===--- AnnotateHighlightings.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 "SemanticHighlighting.h"
9 #include "refactor/Tweak.h"
10 #include "llvm/ADT/StringRef.h"
11 
12 namespace clang {
13 namespace clangd {
14 namespace {
15 
16 /// Annotate all highlighting tokens in the current file. This is a hidden tweak
17 /// which is used to debug semantic highlightings.
18 /// Before:
19 /// void f() { int abc; }
20 /// ^^^^^^^^^^^^^^^^^^^^^
21 /// After:
22 /// void /* entity.name.function.cpp */ f() { int /* variable.cpp */ abc; }
23 class AnnotateHighlightings : public Tweak {
24 public:
25  const char *id() const override final;
26 
27  bool prepare(const Selection &Inputs) override { return true; }
28  Expected<Effect> apply(const Selection &Inputs) override;
29 
30  std::string title() const override { return "Annotate highlighting tokens"; }
31  Intent intent() const override { return Refactor; }
32  bool hidden() const override { return true; }
33 };
34 REGISTER_TWEAK(AnnotateHighlightings)
35 
36 Expected<Tweak::Effect> AnnotateHighlightings::apply(const Selection &Inputs) {
37  const Decl *CommonDecl = nullptr;
38  for (auto N = Inputs.ASTSelection.commonAncestor(); N && !CommonDecl;
39  N = N->Parent)
40  CommonDecl = N->ASTNode.get<Decl>();
41 
42  std::vector<HighlightingToken> HighlightingTokens;
43  if (!CommonDecl) {
44  // Now we hit the TUDecl case where commonAncestor() returns null
45  // intendedly. We only annotate tokens in the main file, so use the default
46  // traversal scope (which is the top level decls of the main file).
47  HighlightingTokens = getSemanticHighlightings(*Inputs.AST);
48  } else {
49  // Store the existing scopes.
50  const auto &BackupScopes = Inputs.AST->getASTContext().getTraversalScope();
51  // Narrow the traversal scope to the selected node.
52  Inputs.AST->getASTContext().setTraversalScope(
53  {const_cast<Decl *>(CommonDecl)});
54  HighlightingTokens = getSemanticHighlightings(*Inputs.AST);
55  // Restore the traversal scope.
56  Inputs.AST->getASTContext().setTraversalScope(BackupScopes);
57  }
58  auto &SM = Inputs.AST->getSourceManager();
59  tooling::Replacements Result;
60  llvm::StringRef FilePath = SM.getFilename(Inputs.Cursor);
61  for (const auto &Token : HighlightingTokens) {
62  assert(Token.R.start.line == Token.R.end.line &&
63  "Token must be at the same line");
64  auto InsertOffset = positionToOffset(Inputs.Code, Token.R.start);
65  if (!InsertOffset)
66  return InsertOffset.takeError();
67 
68  auto InsertReplacement = tooling::Replacement(
69  FilePath, *InsertOffset, 0,
70  ("/* " + toTextMateScope(Token.Kind) + " */").str());
71  if (auto Err = Result.add(InsertReplacement))
72  return std::move(Err);
73  }
74  return Effect::mainFileEdit(SM, std::move(Result));
75 }
76 
77 } // namespace
78 } // namespace clangd
79 } // namespace clang
const FunctionDecl * Decl
llvm::StringRef toTextMateScope(HighlightingKind Kind)
Converts a HighlightingKind to a corresponding TextMate scope (https://manual.macromates.com/en/language_grammars).
#define REGISTER_TWEAK(Subclass)
Definition: Tweak.h:129
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:155
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST)