1 //==-- SemanticHighlighting.h - Generating highlights from the AST-- 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 //
9 // This file supports semantic highlighting: categorizing tokens in the file so
10 // that the editor can color/style them differently.
11 //
12 // This is particularly valuable for C++: its complex and context-dependent
13 // grammar is a challenge for simple syntax-highlighting techniques.
14 //
15 // We support two protocols for providing highlights to the client:
16 // - the `textDocument/semanticTokens` request from LSP 3.16
17 //   https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.16.0-next.1/protocol/src/protocol.semanticTokens.proposed.ts
18 // - the earlier proposed `textDocument/semanticHighlighting` notification
19 //   https://github.com/microsoft/vscode-languageserver-node/pull/367
20 //   This is referred to as "Theia" semantic highlighting in the code.
21 //   It was supported from clangd 9 but should be considered deprecated as of
22 //   clangd 11 and eventually removed.
23 //
24 // Semantic highlightings are calculated for an AST by visiting every AST node
25 // and classifying nodes that are interesting to highlight (variables/function
26 // calls etc.).
27 //
28 //===----------------------------------------------------------------------===//
29 
30 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICHIGHLIGHTING_H
31 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICHIGHLIGHTING_H
32 
33 #include "Protocol.h"
34 #include "llvm/Support/raw_ostream.h"
35 
36 namespace clang {
37 namespace clangd {
38 class ParsedAST;
39 
40 enum class HighlightingKind {
41   Variable = 0,
42   LocalVariable,
43   Parameter,
44   Function,
45   Method,
46   StaticMethod,
47   Field,
48   StaticField,
49   Class,
50   Enum,
51   EnumConstant,
52   Typedef,
53   DependentType,
54   DependentName,
55   Namespace,
56   TemplateParameter,
57   Concept,
58   Primitive,
59   Macro,
60 
61   // This one is different from the other kinds as it's a line style
62   // rather than a token style.
63   InactiveCode,
64 
65   LastKind = InactiveCode
66 };
67 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K);
68 
69 // Contains all information needed for the highlighting a token.
70 struct HighlightingToken {
71   HighlightingKind Kind;
72   Range R;
73 };
74 
75 bool operator==(const HighlightingToken &L, const HighlightingToken &R);
76 bool operator<(const HighlightingToken &L, const HighlightingToken &R);
77 
78 /// Contains all information about highlightings on a single line.
79 struct LineHighlightings {
80   int Line;
81   std::vector<HighlightingToken> Tokens;
82   bool IsInactive;
83 };
84 
85 bool operator==(const LineHighlightings &L, const LineHighlightings &R);
86 
87 // Returns all HighlightingTokens from an AST. Only generates highlights for the
88 // main AST.
89 std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST);
90 
91 std::vector<SemanticToken> toSemanticTokens(llvm::ArrayRef<HighlightingToken>);
92 llvm::StringRef toSemanticTokenType(HighlightingKind Kind);
93 std::vector<SemanticTokensEdit> diffTokens(llvm::ArrayRef<SemanticToken> Before,
94                                            llvm::ArrayRef<SemanticToken> After);
95 
96 /// Converts a HighlightingKind to a corresponding TextMate scope
97 /// (https://manual.macromates.com/en/language_grammars).
98 llvm::StringRef toTextMateScope(HighlightingKind Kind);
99 
100 /// Convert to LSP's semantic highlighting information.
101 std::vector<TheiaSemanticHighlightingInformation>
102 toTheiaSemanticHighlightingInformation(
103     llvm::ArrayRef<LineHighlightings> Tokens);
104 
105 /// Return a line-by-line diff between two highlightings.
106 ///  - if the tokens on a line are the same in both highlightings, this line is
107 ///  omitted.
108 ///  - if a line exists in New but not in Old, the tokens on this line are
109 ///  emitted.
110 ///  - if a line does not exist in New but exists in Old, an empty line is
111 ///  emitted (to tell client to clear the previous highlightings on this line).
112 ///
113 /// REQUIRED: Old and New are sorted.
114 std::vector<LineHighlightings>
115 diffHighlightings(ArrayRef<HighlightingToken> New,
116                   ArrayRef<HighlightingToken> Old);
117 
118 } // namespace clangd
119 } // namespace clang
120 
121 #endif
122