comparison clang-tools-extra/clangd/SemanticHighlighting.cpp @ 221:79ff65ed7e25

LLVM12 Original
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 15 Jun 2021 19:15:29 +0900
parents 0572611fdcc8
children 5f17cb93ff66
comparison
equal deleted inserted replaced
220:42394fc6a535 221:79ff65ed7e25
6 // 6 //
7 //===----------------------------------------------------------------------===// 7 //===----------------------------------------------------------------------===//
8 8
9 #include "SemanticHighlighting.h" 9 #include "SemanticHighlighting.h"
10 #include "FindTarget.h" 10 #include "FindTarget.h"
11 #include "HeuristicResolver.h"
11 #include "ParsedAST.h" 12 #include "ParsedAST.h"
12 #include "Protocol.h" 13 #include "Protocol.h"
13 #include "SourceCode.h" 14 #include "SourceCode.h"
14 #include "support/Logger.h" 15 #include "support/Logger.h"
15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Decl.h" 17 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/DeclCXX.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/DeclTemplate.h"
18 #include "clang/AST/DeclarationName.h" 21 #include "clang/AST/DeclarationName.h"
19 #include "clang/AST/ExprCXX.h" 22 #include "clang/AST/ExprCXX.h"
20 #include "clang/AST/RecursiveASTVisitor.h" 23 #include "clang/AST/RecursiveASTVisitor.h"
21 #include "clang/AST/Type.h" 24 #include "clang/AST/Type.h"
22 #include "clang/AST/TypeLoc.h" 25 #include "clang/AST/TypeLoc.h"
36 namespace { 39 namespace {
37 40
38 /// Some names are not written in the source code and cannot be highlighted, 41 /// Some names are not written in the source code and cannot be highlighted,
39 /// e.g. anonymous classes. This function detects those cases. 42 /// e.g. anonymous classes. This function detects those cases.
40 bool canHighlightName(DeclarationName Name) { 43 bool canHighlightName(DeclarationName Name) {
41 if (Name.getNameKind() == DeclarationName::CXXConstructorName || 44 switch (Name.getNameKind()) {
42 Name.getNameKind() == DeclarationName::CXXUsingDirective) 45 case DeclarationName::Identifier: {
43 return true; 46 auto *II = Name.getAsIdentifierInfo();
44 auto *II = Name.getAsIdentifierInfo(); 47 return II && !II->getName().empty();
45 return II && !II->getName().empty(); 48 }
46 } 49 case DeclarationName::CXXConstructorName:
47 50 case DeclarationName::CXXDestructorName:
48 llvm::Optional<HighlightingKind> kindForType(const Type *TP); 51 return true;
49 llvm::Optional<HighlightingKind> kindForDecl(const NamedDecl *D) { 52 case DeclarationName::ObjCZeroArgSelector:
53 case DeclarationName::ObjCOneArgSelector:
54 case DeclarationName::ObjCMultiArgSelector:
55 // Multi-arg selectors need special handling, and we handle 0/1 arg
56 // selectors there too.
57 return false;
58 case DeclarationName::CXXConversionFunctionName:
59 case DeclarationName::CXXOperatorName:
60 case DeclarationName::CXXDeductionGuideName:
61 case DeclarationName::CXXLiteralOperatorName:
62 case DeclarationName::CXXUsingDirective:
63 return false;
64 }
65 llvm_unreachable("invalid name kind");
66 }
67
68 llvm::Optional<HighlightingKind> kindForType(const Type *TP,
69 const HeuristicResolver *Resolver);
70 llvm::Optional<HighlightingKind>
71 kindForDecl(const NamedDecl *D, const HeuristicResolver *Resolver) {
50 if (auto *USD = dyn_cast<UsingShadowDecl>(D)) { 72 if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
51 if (auto *Target = USD->getTargetDecl()) 73 if (auto *Target = USD->getTargetDecl())
52 D = Target; 74 D = Target;
53 } 75 }
54 if (auto *TD = dyn_cast<TemplateDecl>(D)) { 76 if (auto *TD = dyn_cast<TemplateDecl>(D)) {
55 if (auto *Templated = TD->getTemplatedDecl()) 77 if (auto *Templated = TD->getTemplatedDecl())
56 D = Templated; 78 D = Templated;
57 } 79 }
58 if (auto *TD = dyn_cast<TypedefNameDecl>(D)) { 80 if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
59 // We try to highlight typedefs as their underlying type. 81 // We try to highlight typedefs as their underlying type.
60 if (auto K = kindForType(TD->getUnderlyingType().getTypePtrOrNull())) 82 if (auto K =
83 kindForType(TD->getUnderlyingType().getTypePtrOrNull(), Resolver))
61 return K; 84 return K;
62 // And fallback to a generic kind if this fails. 85 // And fallback to a generic kind if this fails.
63 return HighlightingKind::Typedef; 86 return HighlightingKind::Typedef;
64 } 87 }
65 // We highlight class decls, constructor decls and destructor decls as 88 // We highlight class decls, constructor decls and destructor decls as
69 // We don't want to highlight lambdas like classes. 92 // We don't want to highlight lambdas like classes.
70 if (RD->isLambda()) 93 if (RD->isLambda())
71 return llvm::None; 94 return llvm::None;
72 return HighlightingKind::Class; 95 return HighlightingKind::Class;
73 } 96 }
74 if (isa<ClassTemplateDecl>(D) || isa<RecordDecl>(D) || 97 if (isa<ClassTemplateDecl, RecordDecl, CXXConstructorDecl, ObjCInterfaceDecl,
75 isa<CXXConstructorDecl>(D)) 98 ObjCImplementationDecl>(D))
76 return HighlightingKind::Class; 99 return HighlightingKind::Class;
100 if (isa<ObjCProtocolDecl>(D))
101 return HighlightingKind::Interface;
102 if (isa<ObjCCategoryDecl>(D))
103 return HighlightingKind::Namespace;
77 if (auto *MD = dyn_cast<CXXMethodDecl>(D)) 104 if (auto *MD = dyn_cast<CXXMethodDecl>(D))
78 return MD->isStatic() ? HighlightingKind::StaticMethod 105 return MD->isStatic() ? HighlightingKind::StaticMethod
79 : HighlightingKind::Method; 106 : HighlightingKind::Method;
80 if (isa<FieldDecl>(D)) 107 if (auto *OMD = dyn_cast<ObjCMethodDecl>(D))
108 return OMD->isClassMethod() ? HighlightingKind::StaticMethod
109 : HighlightingKind::Method;
110 if (isa<FieldDecl, ObjCPropertyDecl>(D))
81 return HighlightingKind::Field; 111 return HighlightingKind::Field;
82 if (isa<EnumDecl>(D)) 112 if (isa<EnumDecl>(D))
83 return HighlightingKind::Enum; 113 return HighlightingKind::Enum;
84 if (isa<EnumConstantDecl>(D)) 114 if (isa<EnumConstantDecl>(D))
85 return HighlightingKind::EnumConstant; 115 return HighlightingKind::EnumConstant;
86 if (isa<ParmVarDecl>(D)) 116 if (isa<ParmVarDecl>(D))
87 return HighlightingKind::Parameter; 117 return HighlightingKind::Parameter;
88 if (auto *VD = dyn_cast<VarDecl>(D)) 118 if (auto *VD = dyn_cast<VarDecl>(D)) {
119 if (isa<ImplicitParamDecl>(VD)) // e.g. ObjC Self
120 return llvm::None;
89 return VD->isStaticDataMember() 121 return VD->isStaticDataMember()
90 ? HighlightingKind::StaticField 122 ? HighlightingKind::StaticField
91 : VD->isLocalVarDecl() ? HighlightingKind::LocalVariable 123 : VD->isLocalVarDecl() ? HighlightingKind::LocalVariable
92 : HighlightingKind::Variable; 124 : HighlightingKind::Variable;
93 if (isa<BindingDecl>(D)) 125 }
94 return HighlightingKind::Variable; 126 if (const auto *BD = dyn_cast<BindingDecl>(D))
127 return BD->getDeclContext()->isFunctionOrMethod()
128 ? HighlightingKind::LocalVariable
129 : HighlightingKind::Variable;
95 if (isa<FunctionDecl>(D)) 130 if (isa<FunctionDecl>(D))
96 return HighlightingKind::Function; 131 return HighlightingKind::Function;
97 if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D) || 132 if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D) ||
98 isa<UsingDirectiveDecl>(D)) 133 isa<UsingDirectiveDecl>(D))
99 return HighlightingKind::Namespace; 134 return HighlightingKind::Namespace;
100 if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || 135 if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
101 isa<NonTypeTemplateParmDecl>(D)) 136 isa<NonTypeTemplateParmDecl>(D))
102 return HighlightingKind::TemplateParameter; 137 return HighlightingKind::TemplateParameter;
103 if (isa<ConceptDecl>(D)) 138 if (isa<ConceptDecl>(D))
104 return HighlightingKind::Concept; 139 return HighlightingKind::Concept;
140 if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(D)) {
141 auto Targets = Resolver->resolveUsingValueDecl(UUVD);
142 if (!Targets.empty()) {
143 return kindForDecl(Targets[0], Resolver);
144 }
145 return HighlightingKind::Unknown;
146 }
105 return llvm::None; 147 return llvm::None;
106 } 148 }
107 llvm::Optional<HighlightingKind> kindForType(const Type *TP) { 149 llvm::Optional<HighlightingKind>
150 kindForType(const Type *TP, const HeuristicResolver *Resolver) {
108 if (!TP) 151 if (!TP)
109 return llvm::None; 152 return llvm::None;
110 if (TP->isBuiltinType()) // Builtins are special, they do not have decls. 153 if (TP->isBuiltinType()) // Builtins are special, they do not have decls.
111 return HighlightingKind::Primitive; 154 return HighlightingKind::Primitive;
112 if (auto *TD = dyn_cast<TemplateTypeParmType>(TP)) 155 if (auto *TD = dyn_cast<TemplateTypeParmType>(TP))
113 return kindForDecl(TD->getDecl()); 156 return kindForDecl(TD->getDecl(), Resolver);
157 if (isa<ObjCObjectPointerType>(TP))
158 return HighlightingKind::Class;
114 if (auto *TD = TP->getAsTagDecl()) 159 if (auto *TD = TP->getAsTagDecl())
115 return kindForDecl(TD); 160 return kindForDecl(TD, Resolver);
116 return llvm::None; 161 return llvm::None;
117 } 162 }
118 163
119 llvm::Optional<HighlightingKind> kindForReference(const ReferenceLoc &R) { 164 // Whether T is const in a loose sense - is a variable with this type readonly?
120 llvm::Optional<HighlightingKind> Result; 165 bool isConst(QualType T) {
121 for (const NamedDecl *Decl : R.Targets) { 166 if (T.isNull() || T->isDependentType())
122 if (!canHighlightName(Decl->getDeclName())) 167 return false;
123 return llvm::None; 168 T = T.getNonReferenceType();
124 auto Kind = kindForDecl(Decl); 169 if (T.isConstQualified())
125 if (!Kind || (Result && Kind != Result)) 170 return true;
126 return llvm::None; 171 if (const auto *AT = T->getAsArrayTypeUnsafe())
127 Result = Kind; 172 return isConst(AT->getElementType());
128 } 173 if (isConst(T->getPointeeType()))
129 return Result; 174 return true;
175 return false;
176 }
177
178 // Whether D is const in a loose sense (should it be highlighted as such?)
179 // FIXME: This is separate from whether *a particular usage* can mutate D.
180 // We may want V in V.size() to be readonly even if V is mutable.
181 bool isConst(const Decl *D) {
182 if (llvm::isa<EnumConstantDecl>(D) || llvm::isa<NonTypeTemplateParmDecl>(D))
183 return true;
184 if (llvm::isa<FieldDecl>(D) || llvm::isa<VarDecl>(D) ||
185 llvm::isa<MSPropertyDecl>(D) || llvm::isa<BindingDecl>(D)) {
186 if (isConst(llvm::cast<ValueDecl>(D)->getType()))
187 return true;
188 }
189 if (const auto *OCPD = llvm::dyn_cast<ObjCPropertyDecl>(D)) {
190 if (OCPD->isReadOnly())
191 return true;
192 }
193 if (const auto *MPD = llvm::dyn_cast<MSPropertyDecl>(D)) {
194 if (!MPD->hasSetter())
195 return true;
196 }
197 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
198 if (CMD->isConst())
199 return true;
200 }
201 return false;
202 }
203
204 // "Static" means many things in C++, only some get the "static" modifier.
205 //
206 // Meanings that do:
207 // - Members associated with the class rather than the instance.
208 // This is what 'static' most often means across languages.
209 // - static local variables
210 // These are similarly "detached from their context" by the static keyword.
211 // In practice, these are rarely used inside classes, reducing confusion.
212 //
213 // Meanings that don't:
214 // - Namespace-scoped variables, which have static storage class.
215 // This is implicit, so the keyword "static" isn't so strongly associated.
216 // If we want a modifier for these, "global scope" is probably the concept.
217 // - Namespace-scoped variables/functions explicitly marked "static".
218 // There the keyword changes *linkage* , which is a totally different concept.
219 // If we want to model this, "file scope" would be a nice modifier.
220 //
221 // This is confusing, and maybe we should use another name, but because "static"
222 // is a standard LSP modifier, having one with that name has advantages.
223 bool isStatic(const Decl *D) {
224 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
225 return CMD->isStatic();
226 if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
227 return VD->isStaticDataMember() || VD->isStaticLocal();
228 if (const auto *OPD = llvm::dyn_cast<ObjCPropertyDecl>(D))
229 return OPD->isClassProperty();
230 if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D))
231 return OMD->isClassMethod();
232 return false;
233 }
234
235 bool isAbstract(const Decl *D) {
236 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
237 return CMD->isPure();
238 if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(D))
239 return CRD->hasDefinition() && CRD->isAbstract();
240 return false;
241 }
242
243 bool isDependent(const Decl *D) {
244 if (isa<UnresolvedUsingValueDecl>(D))
245 return true;
246 return false;
247 }
248
249 /// Returns true if `Decl` is considered to be from a default/system library.
250 /// This currently checks the systemness of the file by include type, although
251 /// different heuristics may be used in the future (e.g. sysroot paths).
252 bool isDefaultLibrary(const Decl *D) {
253 SourceLocation Loc = D->getLocation();
254 if (!Loc.isValid())
255 return false;
256 return D->getASTContext().getSourceManager().isInSystemHeader(Loc);
257 }
258
259 bool isDefaultLibrary(const Type *T) {
260 if (!T)
261 return false;
262 const Type *Underlying = T->getPointeeOrArrayElementType();
263 if (Underlying->isBuiltinType())
264 return true;
265 if (auto *TD = dyn_cast<TemplateTypeParmType>(Underlying))
266 return isDefaultLibrary(TD->getDecl());
267 if (auto *TD = Underlying->getAsTagDecl())
268 return isDefaultLibrary(TD);
269 return false;
130 } 270 }
131 271
132 // For a macro usage `DUMP(foo)`, we want: 272 // For a macro usage `DUMP(foo)`, we want:
133 // - DUMP --> "macro" 273 // - DUMP --> "macro"
134 // - foo --> "variable". 274 // - foo --> "variable".
141 return {}; 281 return {};
142 // Tokens expanded from macro args are potentially highlightable. 282 // Tokens expanded from macro args are potentially highlightable.
143 return getHighlightableSpellingToken(SM.getImmediateSpellingLoc(L), SM); 283 return getHighlightableSpellingToken(SM.getImmediateSpellingLoc(L), SM);
144 } 284 }
145 285
146 unsigned evaluateHighlightPriority(HighlightingKind Kind) { 286 unsigned evaluateHighlightPriority(const HighlightingToken &Tok) {
147 enum HighlightPriority { Dependent = 0, Resolved = 1 }; 287 enum HighlightPriority { Dependent = 0, Resolved = 1 };
148 return Kind == HighlightingKind::DependentType || 288 return (Tok.Modifiers & (1 << uint32_t(HighlightingModifier::DependentName)))
149 Kind == HighlightingKind::DependentName
150 ? Dependent 289 ? Dependent
151 : Resolved; 290 : Resolved;
152 } 291 }
153 292
154 // Sometimes we get conflicts between findExplicitReferences() returning 293 // Sometimes we get multiple tokens at the same location:
155 // a heuristic result for a dependent name (e.g. Method) and 294 //
156 // CollectExtraHighlighting returning a fallback dependent highlighting (e.g. 295 // - findExplicitReferences() returns a heuristic result for a dependent name
157 // DependentName). In such cases, resolve the conflict in favour of the 296 // (e.g. Method) and CollectExtraHighlighting returning a fallback dependent
158 // resolved (non-dependent) highlighting. 297 // highlighting (e.g. Unknown+Dependent).
159 // With macros we can get other conflicts (if a spelled token has multiple 298 // - macro arguments are expanded multiple times and have different roles
160 // expansions with different token types) which we can't usefully resolve. 299 // - broken code recovery produces several AST nodes at the same location
300 //
301 // We should either resolve these to a single token, or drop them all.
302 // Our heuristics are:
303 //
304 // - token kinds that come with "dependent-name" modifiers are less reliable
305 // (these tend to be vague, like Type or Unknown)
306 // - if we have multiple equally reliable kinds, drop token rather than guess
307 // - take the union of modifiers from all tokens
308 //
309 // In particular, heuristically resolved dependent names get their heuristic
310 // kind, plus the dependent modifier.
161 llvm::Optional<HighlightingToken> 311 llvm::Optional<HighlightingToken>
162 resolveConflict(ArrayRef<HighlightingToken> Tokens) { 312 resolveConflict(ArrayRef<HighlightingToken> Tokens) {
163 if (Tokens.size() == 1) 313 if (Tokens.size() == 1)
164 return Tokens[0]; 314 return Tokens[0];
165 315
166 if (Tokens.size() != 2) 316 if (Tokens.size() != 2)
167 return llvm::None; 317 return llvm::None;
168 318
169 unsigned Priority1 = evaluateHighlightPriority(Tokens[0].Kind); 319 unsigned Priority1 = evaluateHighlightPriority(Tokens[0]);
170 unsigned Priority2 = evaluateHighlightPriority(Tokens[1].Kind); 320 unsigned Priority2 = evaluateHighlightPriority(Tokens[1]);
171 if (Priority1 == Priority2) 321 if (Priority1 == Priority2 && Tokens[0].Kind != Tokens[1].Kind)
172 return llvm::None; 322 return llvm::None;
173 return Priority1 > Priority2 ? Tokens[0] : Tokens[1]; 323 auto Result = Priority1 > Priority2 ? Tokens[0] : Tokens[1];
324 Result.Modifiers = Tokens[0].Modifiers | Tokens[1].Modifiers;
325 return Result;
174 } 326 }
175 327
176 /// Consumes source locations and maps them to text ranges for highlightings. 328 /// Consumes source locations and maps them to text ranges for highlightings.
177 class HighlightingsBuilder { 329 class HighlightingsBuilder {
178 public: 330 public:
179 HighlightingsBuilder(const ParsedAST &AST) 331 HighlightingsBuilder(const ParsedAST &AST)
180 : TB(AST.getTokens()), SourceMgr(AST.getSourceManager()), 332 : TB(AST.getTokens()), SourceMgr(AST.getSourceManager()),
181 LangOpts(AST.getLangOpts()) {} 333 LangOpts(AST.getLangOpts()) {}
182 334
183 void addToken(HighlightingToken T) { Tokens.push_back(T); } 335 HighlightingToken &addToken(SourceLocation Loc, HighlightingKind Kind) {
184
185 void addToken(SourceLocation Loc, HighlightingKind Kind) {
186 Loc = getHighlightableSpellingToken(Loc, SourceMgr); 336 Loc = getHighlightableSpellingToken(Loc, SourceMgr);
187 if (Loc.isInvalid()) 337 if (Loc.isInvalid())
188 return; 338 return InvalidHighlightingToken;
189 const auto *Tok = TB.spelledTokenAt(Loc); 339 const auto *Tok = TB.spelledTokenAt(Loc);
190 assert(Tok); 340 assert(Tok);
191 341 return addToken(
192 auto Range = halfOpenToRange(SourceMgr, 342 halfOpenToRange(SourceMgr,
193 Tok->range(SourceMgr).toCharRange(SourceMgr)); 343 Tok->range(SourceMgr).toCharRange(SourceMgr)),
194 Tokens.push_back(HighlightingToken{Kind, std::move(Range)}); 344 Kind);
345 }
346
347 HighlightingToken &addToken(Range R, HighlightingKind Kind) {
348 HighlightingToken HT;
349 HT.R = std::move(R);
350 HT.Kind = Kind;
351 Tokens.push_back(std::move(HT));
352 return Tokens.back();
195 } 353 }
196 354
197 std::vector<HighlightingToken> collect(ParsedAST &AST) && { 355 std::vector<HighlightingToken> collect(ParsedAST &AST) && {
198 // Initializer lists can give duplicates of tokens, therefore all tokens 356 // Initializer lists can give duplicates of tokens, therefore all tokens
199 // must be deduplicated. 357 // must be deduplicated.
217 NonConflicting.push_back(*Resolved); 375 NonConflicting.push_back(*Resolved);
218 // TokRef[Conflicting.size()] is the next token with a different range (or 376 // TokRef[Conflicting.size()] is the next token with a different range (or
219 // the end of the Tokens). 377 // the end of the Tokens).
220 TokRef = TokRef.drop_front(Conflicting.size()); 378 TokRef = TokRef.drop_front(Conflicting.size());
221 } 379 }
222 // Add tokens indicating lines skipped by the preprocessor. 380 const auto &SM = AST.getSourceManager();
223 for (const Range &R : AST.getMacros().SkippedRanges) { 381 StringRef MainCode = SM.getBufferOrFake(SM.getMainFileID()).getBuffer();
382
383 // Merge token stream with "inactive line" markers.
384 std::vector<HighlightingToken> WithInactiveLines;
385 auto SortedSkippedRanges = AST.getMacros().SkippedRanges;
386 llvm::sort(SortedSkippedRanges);
387 auto It = NonConflicting.begin();
388 for (const Range &R : SortedSkippedRanges) {
224 // Create one token for each line in the skipped range, so it works 389 // Create one token for each line in the skipped range, so it works
225 // with line-based diffing. 390 // with line-based diffing.
226 assert(R.start.line <= R.end.line); 391 assert(R.start.line <= R.end.line);
227 for (int Line = R.start.line; Line < R.end.line; ++Line) { 392 for (int Line = R.start.line; Line <= R.end.line; ++Line) {
228 // Don't bother computing the offset for the end of the line, just use 393 // If the end of the inactive range is at the beginning
229 // zero. The client will treat this highlighting kind specially, and 394 // of a line, that line is not inactive.
230 // highlight the entire line visually (i.e. not just to where the text 395 if (Line == R.end.line && R.end.character == 0)
231 // on the line ends, but to the end of the screen). 396 continue;
232 NonConflicting.push_back({HighlightingKind::InactiveCode, 397 // Copy tokens before the inactive line
233 {Position{Line, 0}, Position{Line, 0}}}); 398 for (; It != NonConflicting.end() && It->R.start.line < Line; ++It)
399 WithInactiveLines.push_back(std::move(*It));
400 // Add a token for the inactive line itself.
401 auto StartOfLine = positionToOffset(MainCode, Position{Line, 0});
402 if (StartOfLine) {
403 StringRef LineText =
404 MainCode.drop_front(*StartOfLine).take_until([](char C) {
405 return C == '\n';
406 });
407 HighlightingToken HT;
408 WithInactiveLines.emplace_back();
409 WithInactiveLines.back().Kind = HighlightingKind::InactiveCode;
410 WithInactiveLines.back().R.start.line = Line;
411 WithInactiveLines.back().R.end.line = Line;
412 WithInactiveLines.back().R.end.character =
413 static_cast<int>(lspLength(LineText));
414 } else {
415 elog("Failed to convert position to offset: {0}",
416 StartOfLine.takeError());
417 }
418
419 // Skip any other tokens on the inactive line. e.g.
420 // `#ifndef Foo` is considered as part of an inactive region when Foo is
421 // defined, and there is a Foo macro token.
422 // FIXME: we should reduce the scope of the inactive region to not
423 // include the directive itself.
424 while (It != NonConflicting.end() && It->R.start.line == Line)
425 ++It;
234 } 426 }
235 } 427 }
236 // Re-sort the tokens because that's what the diffing expects. 428 // Copy tokens after the last inactive line
237 llvm::sort(NonConflicting); 429 for (; It != NonConflicting.end(); ++It)
238 return NonConflicting; 430 WithInactiveLines.push_back(std::move(*It));
239 } 431 return WithInactiveLines;
432 }
433
434 const HeuristicResolver *getResolver() const { return Resolver; }
240 435
241 private: 436 private:
242 const syntax::TokenBuffer &TB; 437 const syntax::TokenBuffer &TB;
243 const SourceManager &SourceMgr; 438 const SourceManager &SourceMgr;
244 const LangOptions &LangOpts; 439 const LangOptions &LangOpts;
245 std::vector<HighlightingToken> Tokens; 440 std::vector<HighlightingToken> Tokens;
441 const HeuristicResolver *Resolver;
442 // returned from addToken(InvalidLoc)
443 HighlightingToken InvalidHighlightingToken;
246 }; 444 };
445
446 llvm::Optional<HighlightingModifier> scopeModifier(const NamedDecl *D) {
447 const DeclContext *DC = D->getDeclContext();
448 // Injected "Foo" within the class "Foo" has file scope, not class scope.
449 if (auto *R = dyn_cast_or_null<RecordDecl>(D))
450 if (R->isInjectedClassName())
451 DC = DC->getParent();
452 // Lambda captures are considered function scope, not class scope.
453 if (llvm::isa<FieldDecl>(D))
454 if (const auto *RD = llvm::dyn_cast<RecordDecl>(DC))
455 if (RD->isLambda())
456 return HighlightingModifier::FunctionScope;
457 // Walk up the DeclContext hierarchy until we find something interesting.
458 for (; !DC->isFileContext(); DC = DC->getParent()) {
459 if (DC->isFunctionOrMethod())
460 return HighlightingModifier::FunctionScope;
461 if (DC->isRecord())
462 return HighlightingModifier::ClassScope;
463 }
464 // Some template parameters (e.g. those for variable templates) don't have
465 // meaningful DeclContexts. That doesn't mean they're global!
466 if (DC->isTranslationUnit() && D->isTemplateParameter())
467 return llvm::None;
468 // ExternalLinkage threshold could be tweaked, e.g. module-visible as global.
469 if (D->getLinkageInternal() < ExternalLinkage)
470 return HighlightingModifier::FileScope;
471 return HighlightingModifier::GlobalScope;
472 }
473
474 llvm::Optional<HighlightingModifier> scopeModifier(const Type *T) {
475 if (!T)
476 return llvm::None;
477 if (T->isBuiltinType())
478 return HighlightingModifier::GlobalScope;
479 if (auto *TD = dyn_cast<TemplateTypeParmType>(T))
480 return scopeModifier(TD->getDecl());
481 if (auto *TD = T->getAsTagDecl())
482 return scopeModifier(TD);
483 return llvm::None;
484 }
247 485
248 /// Produces highlightings, which are not captured by findExplicitReferences, 486 /// Produces highlightings, which are not captured by findExplicitReferences,
249 /// e.g. highlights dependent names and 'auto' as the underlying type. 487 /// e.g. highlights dependent names and 'auto' as the underlying type.
250 class CollectExtraHighlightings 488 class CollectExtraHighlightings
251 : public RecursiveASTVisitor<CollectExtraHighlightings> { 489 : public RecursiveASTVisitor<CollectExtraHighlightings> {
252 public: 490 public:
253 CollectExtraHighlightings(HighlightingsBuilder &H) : H(H) {} 491 CollectExtraHighlightings(HighlightingsBuilder &H) : H(H) {}
254 492
255 bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) { 493 bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) {
256 if (auto K = kindForType(L.getTypePtr())) 494 if (auto K = kindForType(L.getTypePtr(), H.getResolver())) {
257 H.addToken(L.getBeginLoc(), *K); 495 auto &Tok = H.addToken(L.getBeginLoc(), *K)
496 .addModifier(HighlightingModifier::Deduced);
497 if (auto Mod = scopeModifier(L.getTypePtr()))
498 Tok.addModifier(*Mod);
499 if (isDefaultLibrary(L.getTypePtr()))
500 Tok.addModifier(HighlightingModifier::DefaultLibrary);
501 }
258 return true; 502 return true;
259 } 503 }
260 504
261 bool VisitDeclaratorDecl(DeclaratorDecl *D) { 505 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
262 auto *AT = D->getType()->getContainedAutoType(); 506 auto *AT = D->getType()->getContainedAutoType();
263 if (!AT) 507 if (!AT)
264 return true; 508 return true;
265 if (auto K = kindForType(AT->getDeducedType().getTypePtrOrNull())) 509 if (auto K = kindForType(AT->getDeducedType().getTypePtrOrNull(),
266 H.addToken(D->getTypeSpecStartLoc(), *K); 510 H.getResolver())) {
511 auto &Tok = H.addToken(D->getTypeSpecStartLoc(), *K)
512 .addModifier(HighlightingModifier::Deduced);
513 const Type *Deduced = AT->getDeducedType().getTypePtrOrNull();
514 if (auto Mod = scopeModifier(Deduced))
515 Tok.addModifier(*Mod);
516 if (isDefaultLibrary(Deduced))
517 Tok.addModifier(HighlightingModifier::DefaultLibrary);
518 }
519 return true;
520 }
521
522 // We handle objective-C selectors specially, because one reference can
523 // cover several non-contiguous tokens.
524 void highlightObjCSelector(const ArrayRef<SourceLocation> &Locs, bool Decl,
525 bool Class, bool DefaultLibrary) {
526 HighlightingKind Kind =
527 Class ? HighlightingKind::StaticMethod : HighlightingKind::Method;
528 for (SourceLocation Part : Locs) {
529 auto &Tok =
530 H.addToken(Part, Kind).addModifier(HighlightingModifier::ClassScope);
531 if (Decl)
532 Tok.addModifier(HighlightingModifier::Declaration);
533 if (Class)
534 Tok.addModifier(HighlightingModifier::Static);
535 if (DefaultLibrary)
536 Tok.addModifier(HighlightingModifier::DefaultLibrary);
537 }
538 }
539
540 bool VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
541 llvm::SmallVector<SourceLocation> Locs;
542 OMD->getSelectorLocs(Locs);
543 highlightObjCSelector(Locs, /*Decl=*/true, OMD->isClassMethod(),
544 isDefaultLibrary(OMD));
545 return true;
546 }
547
548 bool VisitObjCMessageExpr(ObjCMessageExpr *OME) {
549 llvm::SmallVector<SourceLocation> Locs;
550 OME->getSelectorLocs(Locs);
551 bool DefaultLibrary = false;
552 if (ObjCMethodDecl *OMD = OME->getMethodDecl())
553 DefaultLibrary = isDefaultLibrary(OMD);
554 highlightObjCSelector(Locs, /*Decl=*/false, OME->isClassMessage(),
555 DefaultLibrary);
267 return true; 556 return true;
268 } 557 }
269 558
270 bool VisitOverloadExpr(OverloadExpr *E) { 559 bool VisitOverloadExpr(OverloadExpr *E) {
271 if (!E->decls().empty()) 560 if (!E->decls().empty())
272 return true; // handled by findExplicitReferences. 561 return true; // handled by findExplicitReferences.
273 H.addToken(E->getNameLoc(), HighlightingKind::DependentName); 562 auto &Tok = H.addToken(E->getNameLoc(), HighlightingKind::Unknown)
563 .addModifier(HighlightingModifier::DependentName);
564 if (llvm::isa<UnresolvedMemberExpr>(E))
565 Tok.addModifier(HighlightingModifier::ClassScope);
566 // other case is UnresolvedLookupExpr, scope is unknown.
274 return true; 567 return true;
275 } 568 }
276 569
277 bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { 570 bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
278 H.addToken(E->getMemberNameInfo().getLoc(), 571 H.addToken(E->getMemberNameInfo().getLoc(), HighlightingKind::Unknown)
279 HighlightingKind::DependentName); 572 .addModifier(HighlightingModifier::DependentName)
573 .addModifier(HighlightingModifier::ClassScope);
280 return true; 574 return true;
281 } 575 }
282 576
283 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { 577 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
284 H.addToken(E->getNameInfo().getLoc(), HighlightingKind::DependentName); 578 H.addToken(E->getNameInfo().getLoc(), HighlightingKind::Unknown)
579 .addModifier(HighlightingModifier::DependentName)
580 .addModifier(HighlightingModifier::ClassScope);
285 return true; 581 return true;
286 } 582 }
287 583
288 bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) { 584 bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
289 H.addToken(L.getNameLoc(), HighlightingKind::DependentType); 585 H.addToken(L.getNameLoc(), HighlightingKind::Type)
586 .addModifier(HighlightingModifier::DependentName)
587 .addModifier(HighlightingModifier::ClassScope);
290 return true; 588 return true;
291 } 589 }
292 590
293 bool VisitDependentTemplateSpecializationTypeLoc( 591 bool VisitDependentTemplateSpecializationTypeLoc(
294 DependentTemplateSpecializationTypeLoc L) { 592 DependentTemplateSpecializationTypeLoc L) {
295 H.addToken(L.getTemplateNameLoc(), HighlightingKind::DependentType); 593 H.addToken(L.getTemplateNameLoc(), HighlightingKind::Type)
296 return true; 594 .addModifier(HighlightingModifier::DependentName)
595 .addModifier(HighlightingModifier::ClassScope);
596 return true;
597 }
598
599 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc L) {
600 // Handle template template arguments only (other arguments are handled by
601 // their Expr, TypeLoc etc values).
602 if (L.getArgument().getKind() != TemplateArgument::Template &&
603 L.getArgument().getKind() != TemplateArgument::TemplateExpansion)
604 return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
605
606 TemplateName N = L.getArgument().getAsTemplateOrTemplatePattern();
607 switch (N.getKind()) {
608 case TemplateName::OverloadedTemplate:
609 // Template template params must always be class templates.
610 // Don't bother to try to work out the scope here.
611 H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class);
612 break;
613 case TemplateName::DependentTemplate:
614 case TemplateName::AssumedTemplate:
615 H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class)
616 .addModifier(HighlightingModifier::DependentName);
617 break;
618 case TemplateName::Template:
619 case TemplateName::QualifiedTemplate:
620 case TemplateName::SubstTemplateTemplateParm:
621 case TemplateName::SubstTemplateTemplateParmPack:
622 // Names that could be resolved to a TemplateDecl are handled elsewhere.
623 break;
624 }
625 return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
297 } 626 }
298 627
299 // findExplicitReferences will walk nested-name-specifiers and 628 // findExplicitReferences will walk nested-name-specifiers and
300 // find anything that can be resolved to a Decl. However, non-leaf 629 // find anything that can be resolved to a Decl. However, non-leaf
301 // components of nested-name-specifiers which are dependent names 630 // components of nested-name-specifiers which are dependent names
302 // (kind "Identifier") cannot be resolved to a decl, so we visit 631 // (kind "Identifier") cannot be resolved to a decl, so we visit
303 // them here. 632 // them here.
304 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) { 633 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) {
305 if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) { 634 if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) {
306 if (NNS->getKind() == NestedNameSpecifier::Identifier) 635 if (NNS->getKind() == NestedNameSpecifier::Identifier)
307 H.addToken(Q.getLocalBeginLoc(), HighlightingKind::DependentType); 636 H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type)
637 .addModifier(HighlightingModifier::DependentName)
638 .addModifier(HighlightingModifier::ClassScope);
308 } 639 }
309 return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q); 640 return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q);
310 } 641 }
311 642
312 private: 643 private:
313 HighlightingsBuilder &H; 644 HighlightingsBuilder &H;
314 }; 645 };
315
316 void write32be(uint32_t I, llvm::raw_ostream &OS) {
317 std::array<char, 4> Buf;
318 llvm::support::endian::write32be(Buf.data(), I);
319 OS.write(Buf.data(), Buf.size());
320 }
321
322 void write16be(uint16_t I, llvm::raw_ostream &OS) {
323 std::array<char, 2> Buf;
324 llvm::support::endian::write16be(Buf.data(), I);
325 OS.write(Buf.data(), Buf.size());
326 }
327
328 // Get the highlightings on \c Line where the first entry of line is at \c
329 // StartLineIt. If it is not at \c StartLineIt an empty vector is returned.
330 ArrayRef<HighlightingToken>
331 takeLine(ArrayRef<HighlightingToken> AllTokens,
332 ArrayRef<HighlightingToken>::iterator StartLineIt, int Line) {
333 return ArrayRef<HighlightingToken>(StartLineIt, AllTokens.end())
334 .take_while([Line](const HighlightingToken &Token) {
335 return Token.R.start.line == Line;
336 });
337 }
338 } // namespace 646 } // namespace
339 647
340 std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) { 648 std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) {
341 auto &C = AST.getASTContext(); 649 auto &C = AST.getASTContext();
342 // Add highlightings for AST nodes. 650 // Add highlightings for AST nodes.
343 HighlightingsBuilder Builder(AST); 651 HighlightingsBuilder Builder(AST);
344 // Highlight 'decltype' and 'auto' as their underlying types. 652 // Highlight 'decltype' and 'auto' as their underlying types.
345 CollectExtraHighlightings(Builder).TraverseAST(C); 653 CollectExtraHighlightings(Builder).TraverseAST(C);
346 // Highlight all decls and references coming from the AST. 654 // Highlight all decls and references coming from the AST.
347 findExplicitReferences(C, [&](ReferenceLoc R) { 655 findExplicitReferences(
348 if (auto Kind = kindForReference(R)) 656 C,
349 Builder.addToken(R.NameLoc, *Kind); 657 [&](ReferenceLoc R) {
350 }); 658 for (const NamedDecl *Decl : R.Targets) {
659 if (!canHighlightName(Decl->getDeclName()))
660 continue;
661 auto Kind = kindForDecl(Decl, AST.getHeuristicResolver());
662 if (!Kind)
663 continue;
664 auto &Tok = Builder.addToken(R.NameLoc, *Kind);
665
666 // The attribute tests don't want to look at the template.
667 if (auto *TD = dyn_cast<TemplateDecl>(Decl)) {
668 if (auto *Templated = TD->getTemplatedDecl())
669 Decl = Templated;
670 }
671 if (auto Mod = scopeModifier(Decl))
672 Tok.addModifier(*Mod);
673 if (isConst(Decl))
674 Tok.addModifier(HighlightingModifier::Readonly);
675 if (isStatic(Decl))
676 Tok.addModifier(HighlightingModifier::Static);
677 if (isAbstract(Decl))
678 Tok.addModifier(HighlightingModifier::Abstract);
679 if (isDependent(Decl))
680 Tok.addModifier(HighlightingModifier::DependentName);
681 if (isDefaultLibrary(Decl))
682 Tok.addModifier(HighlightingModifier::DefaultLibrary);
683 if (Decl->isDeprecated())
684 Tok.addModifier(HighlightingModifier::Deprecated);
685 // Do not treat an UnresolvedUsingValueDecl as a declaration.
686 // It's more common to think of it as a reference to the
687 // underlying declaration.
688 if (R.IsDecl && !isa<UnresolvedUsingValueDecl>(Decl))
689 Tok.addModifier(HighlightingModifier::Declaration);
690 }
691 },
692 AST.getHeuristicResolver());
351 // Add highlightings for macro references. 693 // Add highlightings for macro references.
352 for (const auto &SIDToRefs : AST.getMacros().MacroRefs) { 694 auto AddMacro = [&](const MacroOccurrence &M) {
695 auto &T = Builder.addToken(M.Rng, HighlightingKind::Macro);
696 T.addModifier(HighlightingModifier::GlobalScope);
697 if (M.IsDefinition)
698 T.addModifier(HighlightingModifier::Declaration);
699 };
700 for (const auto &SIDToRefs : AST.getMacros().MacroRefs)
353 for (const auto &M : SIDToRefs.second) 701 for (const auto &M : SIDToRefs.second)
354 Builder.addToken({HighlightingKind::Macro, M}); 702 AddMacro(M);
355 }
356 for (const auto &M : AST.getMacros().UnknownMacros) 703 for (const auto &M : AST.getMacros().UnknownMacros)
357 Builder.addToken({HighlightingKind::Macro, M}); 704 AddMacro(M);
358 705
359 return std::move(Builder).collect(AST); 706 return std::move(Builder).collect(AST);
360 } 707 }
361 708
362 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) { 709 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
377 return OS << "Field"; 724 return OS << "Field";
378 case HighlightingKind::StaticField: 725 case HighlightingKind::StaticField:
379 return OS << "StaticField"; 726 return OS << "StaticField";
380 case HighlightingKind::Class: 727 case HighlightingKind::Class:
381 return OS << "Class"; 728 return OS << "Class";
729 case HighlightingKind::Interface:
730 return OS << "Interface";
382 case HighlightingKind::Enum: 731 case HighlightingKind::Enum:
383 return OS << "Enum"; 732 return OS << "Enum";
384 case HighlightingKind::EnumConstant: 733 case HighlightingKind::EnumConstant:
385 return OS << "EnumConstant"; 734 return OS << "EnumConstant";
386 case HighlightingKind::Typedef: 735 case HighlightingKind::Typedef:
387 return OS << "Typedef"; 736 return OS << "Typedef";
388 case HighlightingKind::DependentType: 737 case HighlightingKind::Type:
389 return OS << "DependentType"; 738 return OS << "Type";
390 case HighlightingKind::DependentName: 739 case HighlightingKind::Unknown:
391 return OS << "DependentName"; 740 return OS << "Unknown";
392 case HighlightingKind::Namespace: 741 case HighlightingKind::Namespace:
393 return OS << "Namespace"; 742 return OS << "Namespace";
394 case HighlightingKind::TemplateParameter: 743 case HighlightingKind::TemplateParameter:
395 return OS << "TemplateParameter"; 744 return OS << "TemplateParameter";
396 case HighlightingKind::Concept: 745 case HighlightingKind::Concept:
402 case HighlightingKind::InactiveCode: 751 case HighlightingKind::InactiveCode:
403 return OS << "InactiveCode"; 752 return OS << "InactiveCode";
404 } 753 }
405 llvm_unreachable("invalid HighlightingKind"); 754 llvm_unreachable("invalid HighlightingKind");
406 } 755 }
407 756 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingModifier K) {
408 std::vector<LineHighlightings> 757 switch (K) {
409 diffHighlightings(ArrayRef<HighlightingToken> New, 758 case HighlightingModifier::Declaration:
410 ArrayRef<HighlightingToken> Old) { 759 return OS << "decl"; // abbrevation for common case
411 assert(std::is_sorted(New.begin(), New.end()) && 760 default:
412 "New must be a sorted vector"); 761 return OS << toSemanticTokenModifier(K);
413 assert(std::is_sorted(Old.begin(), Old.end()) && 762 }
414 "Old must be a sorted vector");
415
416 // FIXME: There's an edge case when tokens span multiple lines. If the first
417 // token on the line started on a line above the current one and the rest of
418 // the line is the equal to the previous one than we will remove all
419 // highlights but the ones for the token spanning multiple lines. This means
420 // that when we get into the LSP layer the only highlights that will be
421 // visible are the ones for the token spanning multiple lines.
422 // Example:
423 // EndOfMultilineToken Token Token Token
424 // If "Token Token Token" don't differ from previously the line is
425 // incorrectly removed. Suggestion to fix is to separate any multiline tokens
426 // into one token for every line it covers. This requires reading from the
427 // file buffer to figure out the length of each line though.
428 std::vector<LineHighlightings> DiffedLines;
429 // ArrayRefs to the current line in the highlightings.
430 ArrayRef<HighlightingToken> NewLine(New.begin(),
431 /*length*/ static_cast<size_t>(0));
432 ArrayRef<HighlightingToken> OldLine(Old.begin(),
433 /*length*/ static_cast<size_t>(0));
434 auto NewEnd = New.end();
435 auto OldEnd = Old.end();
436 auto NextLineNumber = [&]() {
437 int NextNew = NewLine.end() != NewEnd ? NewLine.end()->R.start.line
438 : std::numeric_limits<int>::max();
439 int NextOld = OldLine.end() != OldEnd ? OldLine.end()->R.start.line
440 : std::numeric_limits<int>::max();
441 return std::min(NextNew, NextOld);
442 };
443
444 for (int LineNumber = 0; NewLine.end() < NewEnd || OldLine.end() < OldEnd;
445 LineNumber = NextLineNumber()) {
446 NewLine = takeLine(New, NewLine.end(), LineNumber);
447 OldLine = takeLine(Old, OldLine.end(), LineNumber);
448 if (NewLine != OldLine) {
449 DiffedLines.push_back({LineNumber, NewLine, /*IsInactive=*/false});
450
451 // Turn a HighlightingKind::InactiveCode token into the IsInactive flag.
452 auto &AddedLine = DiffedLines.back();
453 llvm::erase_if(AddedLine.Tokens, [&](const HighlightingToken &T) {
454 if (T.Kind == HighlightingKind::InactiveCode) {
455 AddedLine.IsInactive = true;
456 return true;
457 }
458 return false;
459 });
460 }
461 }
462
463 return DiffedLines;
464 } 763 }
465 764
466 bool operator==(const HighlightingToken &L, const HighlightingToken &R) { 765 bool operator==(const HighlightingToken &L, const HighlightingToken &R) {
467 return std::tie(L.R, L.Kind) == std::tie(R.R, R.Kind); 766 return std::tie(L.R, L.Kind, L.Modifiers) ==
767 std::tie(R.R, R.Kind, R.Modifiers);
468 } 768 }
469 bool operator<(const HighlightingToken &L, const HighlightingToken &R) { 769 bool operator<(const HighlightingToken &L, const HighlightingToken &R) {
470 return std::tie(L.R, L.Kind) < std::tie(R.R, R.Kind); 770 return std::tie(L.R, L.Kind, R.Modifiers) <
471 } 771 std::tie(R.R, R.Kind, R.Modifiers);
472 bool operator==(const LineHighlightings &L, const LineHighlightings &R) {
473 return std::tie(L.Line, L.Tokens) == std::tie(R.Line, R.Tokens);
474 } 772 }
475 773
476 std::vector<SemanticToken> 774 std::vector<SemanticToken>
477 toSemanticTokens(llvm::ArrayRef<HighlightingToken> Tokens) { 775 toSemanticTokens(llvm::ArrayRef<HighlightingToken> Tokens) {
478 assert(std::is_sorted(Tokens.begin(), Tokens.end())); 776 assert(std::is_sorted(Tokens.begin(), Tokens.end()));
479 std::vector<SemanticToken> Result; 777 std::vector<SemanticToken> Result;
480 const HighlightingToken *Last = nullptr; 778 const HighlightingToken *Last = nullptr;
481 for (const HighlightingToken &Tok : Tokens) { 779 for (const HighlightingToken &Tok : Tokens) {
482 // FIXME: support inactive code - we need to provide the actual bounds.
483 if (Tok.Kind == HighlightingKind::InactiveCode)
484 continue;
485 Result.emplace_back(); 780 Result.emplace_back();
486 SemanticToken &Out = Result.back(); 781 SemanticToken &Out = Result.back();
487 // deltaStart/deltaLine are relative if possible. 782 // deltaStart/deltaLine are relative if possible.
488 if (Last) { 783 if (Last) {
489 assert(Tok.R.start.line >= Last->R.start.line); 784 assert(Tok.R.start.line >= Last->R.start.line);
499 Out.deltaStart = Tok.R.start.character; 794 Out.deltaStart = Tok.R.start.character;
500 } 795 }
501 assert(Tok.R.end.line == Tok.R.start.line); 796 assert(Tok.R.end.line == Tok.R.start.line);
502 Out.length = Tok.R.end.character - Tok.R.start.character; 797 Out.length = Tok.R.end.character - Tok.R.start.character;
503 Out.tokenType = static_cast<unsigned>(Tok.Kind); 798 Out.tokenType = static_cast<unsigned>(Tok.Kind);
799 Out.tokenModifiers = Tok.Modifiers;
504 800
505 Last = &Tok; 801 Last = &Tok;
506 } 802 }
507 return Result; 803 return Result;
508 } 804 }
515 case HighlightingKind::Parameter: 811 case HighlightingKind::Parameter:
516 return "parameter"; 812 return "parameter";
517 case HighlightingKind::Function: 813 case HighlightingKind::Function:
518 return "function"; 814 return "function";
519 case HighlightingKind::Method: 815 case HighlightingKind::Method:
520 return "member"; 816 return "method";
521 case HighlightingKind::StaticMethod: 817 case HighlightingKind::StaticMethod:
522 // FIXME: better function/member with static modifier? 818 // FIXME: better method with static modifier?
523 return "function"; 819 return "function";
524 case HighlightingKind::Field: 820 case HighlightingKind::Field:
525 return "member"; 821 return "property";
526 case HighlightingKind::Class: 822 case HighlightingKind::Class:
527 return "class"; 823 return "class";
824 case HighlightingKind::Interface:
825 return "interface";
528 case HighlightingKind::Enum: 826 case HighlightingKind::Enum:
529 return "enum"; 827 return "enum";
530 case HighlightingKind::EnumConstant: 828 case HighlightingKind::EnumConstant:
531 return "enumConstant"; // nonstandard 829 return "enumMember";
532 case HighlightingKind::Typedef: 830 case HighlightingKind::Typedef:
831 case HighlightingKind::Type:
533 return "type"; 832 return "type";
534 case HighlightingKind::DependentType: 833 case HighlightingKind::Unknown:
535 return "dependent"; // nonstandard 834 return "unknown"; // nonstandard
536 case HighlightingKind::DependentName:
537 return "dependent"; // nonstandard
538 case HighlightingKind::Namespace: 835 case HighlightingKind::Namespace:
539 return "namespace"; 836 return "namespace";
540 case HighlightingKind::TemplateParameter: 837 case HighlightingKind::TemplateParameter:
541 return "typeParameter"; 838 return "typeParameter";
542 case HighlightingKind::Concept: 839 case HighlightingKind::Concept:
549 return "comment"; 846 return "comment";
550 } 847 }
551 llvm_unreachable("unhandled HighlightingKind"); 848 llvm_unreachable("unhandled HighlightingKind");
552 } 849 }
553 850
554 std::vector<TheiaSemanticHighlightingInformation> 851 llvm::StringRef toSemanticTokenModifier(HighlightingModifier Modifier) {
555 toTheiaSemanticHighlightingInformation( 852 switch (Modifier) {
556 llvm::ArrayRef<LineHighlightings> Tokens) { 853 case HighlightingModifier::Declaration:
557 if (Tokens.size() == 0) 854 return "declaration";
558 return {}; 855 case HighlightingModifier::Deprecated:
559 856 return "deprecated";
560 // FIXME: Tokens might be multiple lines long (block comments) in this case 857 case HighlightingModifier::Readonly:
561 // this needs to add multiple lines for those tokens. 858 return "readonly";
562 std::vector<TheiaSemanticHighlightingInformation> Lines; 859 case HighlightingModifier::Static:
563 Lines.reserve(Tokens.size()); 860 return "static";
564 for (const auto &Line : Tokens) { 861 case HighlightingModifier::Deduced:
565 llvm::SmallVector<char, 128> LineByteTokens; 862 return "deduced"; // nonstandard
566 llvm::raw_svector_ostream OS(LineByteTokens); 863 case HighlightingModifier::Abstract:
567 for (const auto &Token : Line.Tokens) { 864 return "abstract";
568 // Writes the token to LineByteTokens in the byte format specified by the 865 case HighlightingModifier::DependentName:
569 // LSP proposal. Described below. 866 return "dependentName"; // nonstandard
570 // |<---- 4 bytes ---->|<-- 2 bytes -->|<--- 2 bytes -->| 867 case HighlightingModifier::DefaultLibrary:
571 // | character | length | index | 868 return "defaultLibrary";
572 869 case HighlightingModifier::FunctionScope:
573 write32be(Token.R.start.character, OS); 870 return "functionScope"; // nonstandard
574 write16be(Token.R.end.character - Token.R.start.character, OS); 871 case HighlightingModifier::ClassScope:
575 write16be(static_cast<int>(Token.Kind), OS); 872 return "classScope"; // nonstandard
576 } 873 case HighlightingModifier::FileScope:
577 874 return "fileScope"; // nonstandard
578 Lines.push_back({Line.Line, encodeBase64(LineByteTokens), Line.IsInactive}); 875 case HighlightingModifier::GlobalScope:
579 } 876 return "globalScope"; // nonstandard
580 877 }
581 return Lines; 878 llvm_unreachable("unhandled HighlightingModifier");
582 }
583
584 llvm::StringRef toTextMateScope(HighlightingKind Kind) {
585 // FIXME: Add scopes for C and Objective C.
586 switch (Kind) {
587 case HighlightingKind::Function:
588 return "entity.name.function.cpp";
589 case HighlightingKind::Method:
590 return "entity.name.function.method.cpp";
591 case HighlightingKind::StaticMethod:
592 return "entity.name.function.method.static.cpp";
593 case HighlightingKind::Variable:
594 return "variable.other.cpp";
595 case HighlightingKind::LocalVariable:
596 return "variable.other.local.cpp";
597 case HighlightingKind::Parameter:
598 return "variable.parameter.cpp";
599 case HighlightingKind::Field:
600 return "variable.other.field.cpp";
601 case HighlightingKind::StaticField:
602 return "variable.other.field.static.cpp";
603 case HighlightingKind::Class:
604 return "entity.name.type.class.cpp";
605 case HighlightingKind::Enum:
606 return "entity.name.type.enum.cpp";
607 case HighlightingKind::EnumConstant:
608 return "variable.other.enummember.cpp";
609 case HighlightingKind::Typedef:
610 return "entity.name.type.typedef.cpp";
611 case HighlightingKind::DependentType:
612 return "entity.name.type.dependent.cpp";
613 case HighlightingKind::DependentName:
614 return "entity.name.other.dependent.cpp";
615 case HighlightingKind::Namespace:
616 return "entity.name.namespace.cpp";
617 case HighlightingKind::TemplateParameter:
618 return "entity.name.type.template.cpp";
619 case HighlightingKind::Concept:
620 return "entity.name.type.concept.cpp";
621 case HighlightingKind::Primitive:
622 return "storage.type.primitive.cpp";
623 case HighlightingKind::Macro:
624 return "entity.name.function.preprocessor.cpp";
625 case HighlightingKind::InactiveCode:
626 return "meta.disabled";
627 }
628 llvm_unreachable("unhandled HighlightingKind");
629 } 879 }
630 880
631 std::vector<SemanticTokensEdit> 881 std::vector<SemanticTokensEdit>
632 diffTokens(llvm::ArrayRef<SemanticToken> Old, 882 diffTokens(llvm::ArrayRef<SemanticToken> Old,
633 llvm::ArrayRef<SemanticToken> New) { 883 llvm::ArrayRef<SemanticToken> New) {