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