1 //===--- SemanticHighlighting.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 
9 #include "SemanticHighlighting.h"
10 #include "FindTarget.h"
11 #include "HeuristicResolver.h"
12 #include "ParsedAST.h"
13 #include "Protocol.h"
14 #include "SourceCode.h"
15 #include "support/Logger.h"
16 #include "clang/AST/ASTContext.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclCXX.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/DeclTemplate.h"
21 #include "clang/AST/DeclarationName.h"
22 #include "clang/AST/ExprCXX.h"
23 #include "clang/AST/RecursiveASTVisitor.h"
24 #include "clang/AST/Type.h"
25 #include "clang/AST/TypeLoc.h"
26 #include "clang/Basic/LangOptions.h"
27 #include "clang/Basic/SourceLocation.h"
28 #include "clang/Basic/SourceManager.h"
29 #include "clang/Tooling/Syntax/Tokens.h"
30 #include "llvm/ADT/None.h"
31 #include "llvm/ADT/Optional.h"
32 #include "llvm/ADT/STLExtras.h"
33 #include "llvm/Support/Base64.h"
34 #include "llvm/Support/Casting.h"
35 #include <algorithm>
36 
37 namespace clang {
38 namespace clangd {
39 namespace {
40 
41 /// Some names are not written in the source code and cannot be highlighted,
42 /// e.g. anonymous classes. This function detects those cases.
43 bool canHighlightName(DeclarationName Name) {
44   switch (Name.getNameKind()) {
45   case DeclarationName::Identifier: {
46     auto *II = Name.getAsIdentifierInfo();
47     return II && !II->getName().empty();
48   }
49   case DeclarationName::CXXConstructorName:
50   case DeclarationName::CXXDestructorName:
51     return true;
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) {
72   if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
73     if (auto *Target = USD->getTargetDecl())
74       D = Target;
75   }
76   if (auto *TD = dyn_cast<TemplateDecl>(D)) {
77     if (auto *Templated = TD->getTemplatedDecl())
78       D = Templated;
79   }
80   if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
81     // We try to highlight typedefs as their underlying type.
82     if (auto K =
83             kindForType(TD->getUnderlyingType().getTypePtrOrNull(), Resolver))
84       return K;
85     // And fallback to a generic kind if this fails.
86     return HighlightingKind::Typedef;
87   }
88   // We highlight class decls, constructor decls and destructor decls as
89   // `Class` type. The destructor decls are handled in `VisitTagTypeLoc` (we
90   // will visit a TypeLoc where the underlying Type is a CXXRecordDecl).
91   if (auto *RD = llvm::dyn_cast<RecordDecl>(D)) {
92     // We don't want to highlight lambdas like classes.
93     if (RD->isLambda())
94       return llvm::None;
95     return HighlightingKind::Class;
96   }
97   if (isa<ClassTemplateDecl, RecordDecl, CXXConstructorDecl, ObjCInterfaceDecl,
98           ObjCImplementationDecl>(D))
99     return HighlightingKind::Class;
100   if (isa<ObjCProtocolDecl>(D))
101     return HighlightingKind::Interface;
102   if (isa<ObjCCategoryDecl>(D))
103     return HighlightingKind::Namespace;
104   if (auto *MD = dyn_cast<CXXMethodDecl>(D))
105     return MD->isStatic() ? HighlightingKind::StaticMethod
106                           : HighlightingKind::Method;
107   if (auto *OMD = dyn_cast<ObjCMethodDecl>(D))
108     return OMD->isClassMethod() ? HighlightingKind::StaticMethod
109                                 : HighlightingKind::Method;
110   if (isa<FieldDecl, ObjCPropertyDecl>(D))
111     return HighlightingKind::Field;
112   if (isa<EnumDecl>(D))
113     return HighlightingKind::Enum;
114   if (isa<EnumConstantDecl>(D))
115     return HighlightingKind::EnumConstant;
116   if (isa<ParmVarDecl>(D))
117     return HighlightingKind::Parameter;
118   if (auto *VD = dyn_cast<VarDecl>(D)) {
119     if (isa<ImplicitParamDecl>(VD)) // e.g. ObjC Self
120       return llvm::None;
121     return VD->isStaticDataMember()
122                ? HighlightingKind::StaticField
123                : VD->isLocalVarDecl() ? HighlightingKind::LocalVariable
124                                       : HighlightingKind::Variable;
125   }
126   if (const auto *BD = dyn_cast<BindingDecl>(D))
127     return BD->getDeclContext()->isFunctionOrMethod()
128                ? HighlightingKind::LocalVariable
129                : HighlightingKind::Variable;
130   if (isa<FunctionDecl>(D))
131     return HighlightingKind::Function;
132   if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D) ||
133       isa<UsingDirectiveDecl>(D))
134     return HighlightingKind::Namespace;
135   if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
136       isa<NonTypeTemplateParmDecl>(D))
137     return HighlightingKind::TemplateParameter;
138   if (isa<ConceptDecl>(D))
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   }
147   return llvm::None;
148 }
149 llvm::Optional<HighlightingKind>
150 kindForType(const Type *TP, const HeuristicResolver *Resolver) {
151   if (!TP)
152     return llvm::None;
153   if (TP->isBuiltinType()) // Builtins are special, they do not have decls.
154     return HighlightingKind::Primitive;
155   if (auto *TD = dyn_cast<TemplateTypeParmType>(TP))
156     return kindForDecl(TD->getDecl(), Resolver);
157   if (isa<ObjCObjectPointerType>(TP))
158     return HighlightingKind::Class;
159   if (auto *TD = TP->getAsTagDecl())
160     return kindForDecl(TD, Resolver);
161   return llvm::None;
162 }
163 
164 // Whether T is const in a loose sense - is a variable with this type readonly?
165 bool isConst(QualType T) {
166   if (T.isNull() || T->isDependentType())
167     return false;
168   T = T.getNonReferenceType();
169   if (T.isConstQualified())
170     return true;
171   if (const auto *AT = T->getAsArrayTypeUnsafe())
172     return isConst(AT->getElementType());
173   if (isConst(T->getPointeeType()))
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 isVirtual(const Decl *D) {
244   if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
245     return CMD->isVirtual();
246   return false;
247 }
248 
249 bool isDependent(const Decl *D) {
250   if (isa<UnresolvedUsingValueDecl>(D))
251     return true;
252   return false;
253 }
254 
255 /// Returns true if `Decl` is considered to be from a default/system library.
256 /// This currently checks the systemness of the file by include type, although
257 /// different heuristics may be used in the future (e.g. sysroot paths).
258 bool isDefaultLibrary(const Decl *D) {
259   SourceLocation Loc = D->getLocation();
260   if (!Loc.isValid())
261     return false;
262   return D->getASTContext().getSourceManager().isInSystemHeader(Loc);
263 }
264 
265 bool isDefaultLibrary(const Type *T) {
266   if (!T)
267     return false;
268   const Type *Underlying = T->getPointeeOrArrayElementType();
269   if (Underlying->isBuiltinType())
270     return true;
271   if (auto *TD = dyn_cast<TemplateTypeParmType>(Underlying))
272     return isDefaultLibrary(TD->getDecl());
273   if (auto *TD = Underlying->getAsTagDecl())
274     return isDefaultLibrary(TD);
275   return false;
276 }
277 
278 // For a macro usage `DUMP(foo)`, we want:
279 //  - DUMP --> "macro"
280 //  - foo --> "variable".
281 SourceLocation getHighlightableSpellingToken(SourceLocation L,
282                                              const SourceManager &SM) {
283   if (L.isFileID())
284     return SM.isWrittenInMainFile(L) ? L : SourceLocation{};
285   // Tokens expanded from the macro body contribute no highlightings.
286   if (!SM.isMacroArgExpansion(L))
287     return {};
288   // Tokens expanded from macro args are potentially highlightable.
289   return getHighlightableSpellingToken(SM.getImmediateSpellingLoc(L), SM);
290 }
291 
292 unsigned evaluateHighlightPriority(const HighlightingToken &Tok) {
293   enum HighlightPriority { Dependent = 0, Resolved = 1 };
294   return (Tok.Modifiers & (1 << uint32_t(HighlightingModifier::DependentName)))
295              ? Dependent
296              : Resolved;
297 }
298 
299 // Sometimes we get multiple tokens at the same location:
300 //
301 // - findExplicitReferences() returns a heuristic result for a dependent name
302 //   (e.g. Method) and CollectExtraHighlighting returning a fallback dependent
303 //   highlighting (e.g. Unknown+Dependent).
304 // - macro arguments are expanded multiple times and have different roles
305 // - broken code recovery produces several AST nodes at the same location
306 //
307 // We should either resolve these to a single token, or drop them all.
308 // Our heuristics are:
309 //
310 // - token kinds that come with "dependent-name" modifiers are less reliable
311 //   (these tend to be vague, like Type or Unknown)
312 // - if we have multiple equally reliable kinds, drop token rather than guess
313 // - take the union of modifiers from all tokens
314 //
315 // In particular, heuristically resolved dependent names get their heuristic
316 // kind, plus the dependent modifier.
317 llvm::Optional<HighlightingToken>
318 resolveConflict(ArrayRef<HighlightingToken> Tokens) {
319   if (Tokens.size() == 1)
320     return Tokens[0];
321 
322   if (Tokens.size() != 2)
323     return llvm::None;
324 
325   unsigned Priority1 = evaluateHighlightPriority(Tokens[0]);
326   unsigned Priority2 = evaluateHighlightPriority(Tokens[1]);
327   if (Priority1 == Priority2 && Tokens[0].Kind != Tokens[1].Kind)
328     return llvm::None;
329   auto Result = Priority1 > Priority2 ? Tokens[0] : Tokens[1];
330   Result.Modifiers = Tokens[0].Modifiers | Tokens[1].Modifiers;
331   return Result;
332 }
333 
334 /// Consumes source locations and maps them to text ranges for highlightings.
335 class HighlightingsBuilder {
336 public:
337   HighlightingsBuilder(const ParsedAST &AST)
338       : TB(AST.getTokens()), SourceMgr(AST.getSourceManager()),
339         LangOpts(AST.getLangOpts()) {}
340 
341   HighlightingToken &addToken(SourceLocation Loc, HighlightingKind Kind) {
342     auto Range = getRangeForSourceLocation(Loc);
343     if (!Range)
344       return InvalidHighlightingToken;
345 
346     return addToken(*Range, Kind);
347   }
348 
349   HighlightingToken &addToken(Range R, HighlightingKind Kind) {
350     HighlightingToken HT;
351     HT.R = std::move(R);
352     HT.Kind = Kind;
353     Tokens.push_back(std::move(HT));
354     return Tokens.back();
355   }
356 
357   void addExtraModifier(SourceLocation Loc, HighlightingModifier Modifier) {
358     if (auto Range = getRangeForSourceLocation(Loc))
359       ExtraModifiers[*Range].push_back(Modifier);
360   }
361 
362   std::vector<HighlightingToken> collect(ParsedAST &AST) && {
363     // Initializer lists can give duplicates of tokens, therefore all tokens
364     // must be deduplicated.
365     llvm::sort(Tokens);
366     auto Last = std::unique(Tokens.begin(), Tokens.end());
367     Tokens.erase(Last, Tokens.end());
368 
369     // Macros can give tokens that have the same source range but conflicting
370     // kinds. In this case all tokens sharing this source range should be
371     // removed.
372     std::vector<HighlightingToken> NonConflicting;
373     NonConflicting.reserve(Tokens.size());
374     for (ArrayRef<HighlightingToken> TokRef = Tokens; !TokRef.empty();) {
375       ArrayRef<HighlightingToken> Conflicting =
376           TokRef.take_while([&](const HighlightingToken &T) {
377             // TokRef is guaranteed at least one element here because otherwise
378             // this predicate would never fire.
379             return T.R == TokRef.front().R;
380           });
381       if (auto Resolved = resolveConflict(Conflicting)) {
382         // Apply extra collected highlighting modifiers
383         auto Modifiers = ExtraModifiers.find(Resolved->R);
384         if (Modifiers != ExtraModifiers.end()) {
385           for (HighlightingModifier Mod : Modifiers->second) {
386             Resolved->addModifier(Mod);
387           }
388         }
389 
390         NonConflicting.push_back(*Resolved);
391       }
392       // TokRef[Conflicting.size()] is the next token with a different range (or
393       // the end of the Tokens).
394       TokRef = TokRef.drop_front(Conflicting.size());
395     }
396 
397     const auto &SM = AST.getSourceManager();
398     StringRef MainCode = SM.getBufferOrFake(SM.getMainFileID()).getBuffer();
399 
400     // Merge token stream with "inactive line" markers.
401     std::vector<HighlightingToken> WithInactiveLines;
402     auto SortedSkippedRanges = AST.getMacros().SkippedRanges;
403     llvm::sort(SortedSkippedRanges);
404     auto It = NonConflicting.begin();
405     for (const Range &R : SortedSkippedRanges) {
406       // Create one token for each line in the skipped range, so it works
407       // with line-based diffing.
408       assert(R.start.line <= R.end.line);
409       for (int Line = R.start.line; Line <= R.end.line; ++Line) {
410         // If the end of the inactive range is at the beginning
411         // of a line, that line is not inactive.
412         if (Line == R.end.line && R.end.character == 0)
413           continue;
414         // Copy tokens before the inactive line
415         for (; It != NonConflicting.end() && It->R.start.line < Line; ++It)
416           WithInactiveLines.push_back(std::move(*It));
417         // Add a token for the inactive line itself.
418         auto StartOfLine = positionToOffset(MainCode, Position{Line, 0});
419         if (StartOfLine) {
420           StringRef LineText =
421               MainCode.drop_front(*StartOfLine).take_until([](char C) {
422                 return C == '\n';
423               });
424           HighlightingToken HT;
425           WithInactiveLines.emplace_back();
426           WithInactiveLines.back().Kind = HighlightingKind::InactiveCode;
427           WithInactiveLines.back().R.start.line = Line;
428           WithInactiveLines.back().R.end.line = Line;
429           WithInactiveLines.back().R.end.character =
430               static_cast<int>(lspLength(LineText));
431         } else {
432           elog("Failed to convert position to offset: {0}",
433                StartOfLine.takeError());
434         }
435 
436         // Skip any other tokens on the inactive line. e.g.
437         // `#ifndef Foo` is considered as part of an inactive region when Foo is
438         // defined, and there is a Foo macro token.
439         // FIXME: we should reduce the scope of the inactive region to not
440         // include the directive itself.
441         while (It != NonConflicting.end() && It->R.start.line == Line)
442           ++It;
443       }
444     }
445     // Copy tokens after the last inactive line
446     for (; It != NonConflicting.end(); ++It)
447       WithInactiveLines.push_back(std::move(*It));
448     return WithInactiveLines;
449   }
450 
451   const HeuristicResolver *getResolver() const { return Resolver; }
452 
453 private:
454   llvm::Optional<Range> getRangeForSourceLocation(SourceLocation Loc) {
455     Loc = getHighlightableSpellingToken(Loc, SourceMgr);
456     if (Loc.isInvalid())
457       return llvm::None;
458 
459     const auto *Tok = TB.spelledTokenAt(Loc);
460     assert(Tok);
461 
462     return halfOpenToRange(SourceMgr,
463                            Tok->range(SourceMgr).toCharRange(SourceMgr));
464   }
465 
466   const syntax::TokenBuffer &TB;
467   const SourceManager &SourceMgr;
468   const LangOptions &LangOpts;
469   std::vector<HighlightingToken> Tokens;
470   std::map<Range, llvm::SmallVector<HighlightingModifier, 1>> ExtraModifiers;
471   const HeuristicResolver *Resolver;
472   // returned from addToken(InvalidLoc)
473   HighlightingToken InvalidHighlightingToken;
474 };
475 
476 llvm::Optional<HighlightingModifier> scopeModifier(const NamedDecl *D) {
477   const DeclContext *DC = D->getDeclContext();
478   // Injected "Foo" within the class "Foo" has file scope, not class scope.
479   if (auto *R = dyn_cast_or_null<RecordDecl>(D))
480     if (R->isInjectedClassName())
481       DC = DC->getParent();
482   // Lambda captures are considered function scope, not class scope.
483   if (llvm::isa<FieldDecl>(D))
484     if (const auto *RD = llvm::dyn_cast<RecordDecl>(DC))
485       if (RD->isLambda())
486         return HighlightingModifier::FunctionScope;
487   // Walk up the DeclContext hierarchy until we find something interesting.
488   for (; !DC->isFileContext(); DC = DC->getParent()) {
489     if (DC->isFunctionOrMethod())
490       return HighlightingModifier::FunctionScope;
491     if (DC->isRecord())
492       return HighlightingModifier::ClassScope;
493   }
494   // Some template parameters (e.g. those for variable templates) don't have
495   // meaningful DeclContexts. That doesn't mean they're global!
496   if (DC->isTranslationUnit() && D->isTemplateParameter())
497     return llvm::None;
498   // ExternalLinkage threshold could be tweaked, e.g. module-visible as global.
499   if (D->getLinkageInternal() < ExternalLinkage)
500     return HighlightingModifier::FileScope;
501   return HighlightingModifier::GlobalScope;
502 }
503 
504 llvm::Optional<HighlightingModifier> scopeModifier(const Type *T) {
505   if (!T)
506     return llvm::None;
507   if (T->isBuiltinType())
508     return HighlightingModifier::GlobalScope;
509   if (auto *TD = dyn_cast<TemplateTypeParmType>(T))
510     return scopeModifier(TD->getDecl());
511   if (auto *TD = T->getAsTagDecl())
512     return scopeModifier(TD);
513   return llvm::None;
514 }
515 
516 /// Produces highlightings, which are not captured by findExplicitReferences,
517 /// e.g. highlights dependent names and 'auto' as the underlying type.
518 class CollectExtraHighlightings
519     : public RecursiveASTVisitor<CollectExtraHighlightings> {
520 public:
521   CollectExtraHighlightings(HighlightingsBuilder &H) : H(H) {}
522 
523   bool VisitCXXConstructExpr(CXXConstructExpr *E) {
524     highlightMutableReferenceArguments(E->getConstructor(),
525                                        {E->getArgs(), E->getNumArgs()});
526 
527     return true;
528   }
529 
530   bool VisitCallExpr(CallExpr *E) {
531     // Highlighting parameters passed by non-const reference does not really
532     // make sense for literals...
533     if (isa<UserDefinedLiteral>(E))
534       return true;
535 
536     // FIXME ...here it would make sense though.
537     if (isa<CXXOperatorCallExpr>(E))
538       return true;
539 
540     highlightMutableReferenceArguments(
541         dyn_cast_or_null<FunctionDecl>(E->getCalleeDecl()),
542         {E->getArgs(), E->getNumArgs()});
543 
544     return true;
545   }
546 
547   void
548   highlightMutableReferenceArguments(const FunctionDecl *FD,
549                                      llvm::ArrayRef<const Expr *const> Args) {
550     if (!FD)
551       return;
552 
553     if (auto *ProtoType = FD->getType()->getAs<FunctionProtoType>()) {
554       // Iterate over the types of the function parameters.
555       // If any of them are non-const reference paramteres, add it as a
556       // highlighting modifier to the corresponding expression
557       for (size_t I = 0;
558            I < std::min(size_t(ProtoType->getNumParams()), Args.size()); ++I) {
559         auto T = ProtoType->getParamType(I);
560 
561         // Is this parameter passed by non-const reference?
562         // FIXME The condition !T->idDependentType() could be relaxed a bit,
563         // e.g. std::vector<T>& is dependent but we would want to highlight it
564         if (T->isLValueReferenceType() &&
565             !T.getNonReferenceType().isConstQualified() &&
566             !T->isDependentType()) {
567           if (auto *Arg = Args[I]) {
568             llvm::Optional<SourceLocation> Location;
569 
570             // FIXME Add "unwrapping" for ArraySubscriptExpr and UnaryOperator,
571             //  e.g. highlight `a` in `a[i]`
572             // FIXME Handle dependent expression types
573             if (auto *DR = dyn_cast<DeclRefExpr>(Arg)) {
574               Location = DR->getLocation();
575             } else if (auto *M = dyn_cast<MemberExpr>(Arg)) {
576               Location = M->getMemberLoc();
577             }
578 
579             if (Location)
580               H.addExtraModifier(*Location,
581                                  HighlightingModifier::UsedAsMutableReference);
582           }
583         }
584       }
585     }
586   }
587 
588   bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) {
589     if (auto K = kindForType(L.getTypePtr(), H.getResolver())) {
590       auto &Tok = H.addToken(L.getBeginLoc(), *K)
591                       .addModifier(HighlightingModifier::Deduced);
592       if (auto Mod = scopeModifier(L.getTypePtr()))
593         Tok.addModifier(*Mod);
594       if (isDefaultLibrary(L.getTypePtr()))
595         Tok.addModifier(HighlightingModifier::DefaultLibrary);
596     }
597     return true;
598   }
599 
600   bool VisitDeclaratorDecl(DeclaratorDecl *D) {
601     auto *AT = D->getType()->getContainedAutoType();
602     if (!AT)
603       return true;
604     auto K =
605         kindForType(AT->getDeducedType().getTypePtrOrNull(), H.getResolver());
606     if (!K)
607       return true;
608     SourceLocation StartLoc = D->getTypeSpecStartLoc();
609     // The AutoType may not have a corresponding token, e.g. in the case of
610     // init-captures. In this case, StartLoc overlaps with the location
611     // of the decl itself, and producing a token for the type here would result
612     // in both it and the token for the decl being dropped due to conflict.
613     if (StartLoc == D->getLocation())
614       return true;
615     auto &Tok =
616         H.addToken(StartLoc, *K).addModifier(HighlightingModifier::Deduced);
617     const Type *Deduced = AT->getDeducedType().getTypePtrOrNull();
618     if (auto Mod = scopeModifier(Deduced))
619       Tok.addModifier(*Mod);
620     if (isDefaultLibrary(Deduced))
621       Tok.addModifier(HighlightingModifier::DefaultLibrary);
622     return true;
623   }
624 
625   // We handle objective-C selectors specially, because one reference can
626   // cover several non-contiguous tokens.
627   void highlightObjCSelector(const ArrayRef<SourceLocation> &Locs, bool Decl,
628                              bool Class, bool DefaultLibrary) {
629     HighlightingKind Kind =
630         Class ? HighlightingKind::StaticMethod : HighlightingKind::Method;
631     for (SourceLocation Part : Locs) {
632       auto &Tok =
633           H.addToken(Part, Kind).addModifier(HighlightingModifier::ClassScope);
634       if (Decl)
635         Tok.addModifier(HighlightingModifier::Declaration);
636       if (Class)
637         Tok.addModifier(HighlightingModifier::Static);
638       if (DefaultLibrary)
639         Tok.addModifier(HighlightingModifier::DefaultLibrary);
640     }
641   }
642 
643   bool VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
644     llvm::SmallVector<SourceLocation> Locs;
645     OMD->getSelectorLocs(Locs);
646     highlightObjCSelector(Locs, /*Decl=*/true, OMD->isClassMethod(),
647                           isDefaultLibrary(OMD));
648     return true;
649   }
650 
651   bool VisitObjCMessageExpr(ObjCMessageExpr *OME) {
652     llvm::SmallVector<SourceLocation> Locs;
653     OME->getSelectorLocs(Locs);
654     bool DefaultLibrary = false;
655     if (ObjCMethodDecl *OMD = OME->getMethodDecl())
656       DefaultLibrary = isDefaultLibrary(OMD);
657     highlightObjCSelector(Locs, /*Decl=*/false, OME->isClassMessage(),
658                           DefaultLibrary);
659     return true;
660   }
661 
662   // Objective-C allows you to use property syntax `self.prop` as sugar for
663   // `[self prop]` and `[self setProp:]` when there's no explicit `@property`
664   // for `prop` as well as for class properties. We treat this like a property
665   // even though semantically it's equivalent to a method expression.
666   void highlightObjCImplicitPropertyRef(const ObjCMethodDecl *OMD,
667                                         SourceLocation Loc) {
668     auto &Tok = H.addToken(Loc, HighlightingKind::Field)
669                     .addModifier(HighlightingModifier::ClassScope);
670     if (OMD->isClassMethod())
671       Tok.addModifier(HighlightingModifier::Static);
672     if (isDefaultLibrary(OMD))
673       Tok.addModifier(HighlightingModifier::DefaultLibrary);
674   }
675 
676   bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *OPRE) {
677     // We need to handle implicit properties here since they will appear to
678     // reference `ObjCMethodDecl` via an implicit `ObjCMessageExpr`, so normal
679     // highlighting will not work.
680     if (!OPRE->isImplicitProperty())
681       return true;
682     // A single property expr can reference both a getter and setter, but we can
683     // only provide a single semantic token, so prefer the getter. In most cases
684     // the end result should be the same, although it's technically possible
685     // that the user defines a setter for a system SDK.
686     if (OPRE->isMessagingGetter()) {
687       highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertyGetter(),
688                                        OPRE->getLocation());
689       return true;
690     }
691     if (OPRE->isMessagingSetter()) {
692       highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertySetter(),
693                                        OPRE->getLocation());
694     }
695     return true;
696   }
697 
698   bool VisitOverloadExpr(OverloadExpr *E) {
699     if (!E->decls().empty())
700       return true; // handled by findExplicitReferences.
701     auto &Tok = H.addToken(E->getNameLoc(), HighlightingKind::Unknown)
702                     .addModifier(HighlightingModifier::DependentName);
703     if (llvm::isa<UnresolvedMemberExpr>(E))
704       Tok.addModifier(HighlightingModifier::ClassScope);
705     // other case is UnresolvedLookupExpr, scope is unknown.
706     return true;
707   }
708 
709   bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
710     H.addToken(E->getMemberNameInfo().getLoc(), HighlightingKind::Unknown)
711         .addModifier(HighlightingModifier::DependentName)
712         .addModifier(HighlightingModifier::ClassScope);
713     return true;
714   }
715 
716   bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
717     H.addToken(E->getNameInfo().getLoc(), HighlightingKind::Unknown)
718         .addModifier(HighlightingModifier::DependentName)
719         .addModifier(HighlightingModifier::ClassScope);
720     return true;
721   }
722 
723   bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
724     H.addToken(L.getNameLoc(), HighlightingKind::Type)
725         .addModifier(HighlightingModifier::DependentName)
726         .addModifier(HighlightingModifier::ClassScope);
727     return true;
728   }
729 
730   bool VisitDependentTemplateSpecializationTypeLoc(
731       DependentTemplateSpecializationTypeLoc L) {
732     H.addToken(L.getTemplateNameLoc(), HighlightingKind::Type)
733         .addModifier(HighlightingModifier::DependentName)
734         .addModifier(HighlightingModifier::ClassScope);
735     return true;
736   }
737 
738   bool TraverseTemplateArgumentLoc(TemplateArgumentLoc L) {
739     // Handle template template arguments only (other arguments are handled by
740     // their Expr, TypeLoc etc values).
741     if (L.getArgument().getKind() != TemplateArgument::Template &&
742         L.getArgument().getKind() != TemplateArgument::TemplateExpansion)
743       return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
744 
745     TemplateName N = L.getArgument().getAsTemplateOrTemplatePattern();
746     switch (N.getKind()) {
747     case TemplateName::OverloadedTemplate:
748       // Template template params must always be class templates.
749       // Don't bother to try to work out the scope here.
750       H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class);
751       break;
752     case TemplateName::DependentTemplate:
753     case TemplateName::AssumedTemplate:
754       H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class)
755           .addModifier(HighlightingModifier::DependentName);
756       break;
757     case TemplateName::Template:
758     case TemplateName::QualifiedTemplate:
759     case TemplateName::SubstTemplateTemplateParm:
760     case TemplateName::SubstTemplateTemplateParmPack:
761       // Names that could be resolved to a TemplateDecl are handled elsewhere.
762       break;
763     }
764     return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
765   }
766 
767   // findExplicitReferences will walk nested-name-specifiers and
768   // find anything that can be resolved to a Decl. However, non-leaf
769   // components of nested-name-specifiers which are dependent names
770   // (kind "Identifier") cannot be resolved to a decl, so we visit
771   // them here.
772   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) {
773     if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) {
774       if (NNS->getKind() == NestedNameSpecifier::Identifier)
775         H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type)
776             .addModifier(HighlightingModifier::DependentName)
777             .addModifier(HighlightingModifier::ClassScope);
778     }
779     return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q);
780   }
781 
782 private:
783   HighlightingsBuilder &H;
784 };
785 } // namespace
786 
787 std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) {
788   auto &C = AST.getASTContext();
789   // Add highlightings for AST nodes.
790   HighlightingsBuilder Builder(AST);
791   // Highlight 'decltype' and 'auto' as their underlying types.
792   CollectExtraHighlightings(Builder).TraverseAST(C);
793   // Highlight all decls and references coming from the AST.
794   findExplicitReferences(
795       C,
796       [&](ReferenceLoc R) {
797         for (const NamedDecl *Decl : R.Targets) {
798           if (!canHighlightName(Decl->getDeclName()))
799             continue;
800           auto Kind = kindForDecl(Decl, AST.getHeuristicResolver());
801           if (!Kind)
802             continue;
803           auto &Tok = Builder.addToken(R.NameLoc, *Kind);
804 
805           // The attribute tests don't want to look at the template.
806           if (auto *TD = dyn_cast<TemplateDecl>(Decl)) {
807             if (auto *Templated = TD->getTemplatedDecl())
808               Decl = Templated;
809           }
810           if (auto Mod = scopeModifier(Decl))
811             Tok.addModifier(*Mod);
812           if (isConst(Decl))
813             Tok.addModifier(HighlightingModifier::Readonly);
814           if (isStatic(Decl))
815             Tok.addModifier(HighlightingModifier::Static);
816           if (isAbstract(Decl))
817             Tok.addModifier(HighlightingModifier::Abstract);
818           if (isVirtual(Decl))
819             Tok.addModifier(HighlightingModifier::Virtual);
820           if (isDependent(Decl))
821             Tok.addModifier(HighlightingModifier::DependentName);
822           if (isDefaultLibrary(Decl))
823             Tok.addModifier(HighlightingModifier::DefaultLibrary);
824           if (Decl->isDeprecated())
825             Tok.addModifier(HighlightingModifier::Deprecated);
826           // Do not treat an UnresolvedUsingValueDecl as a declaration.
827           // It's more common to think of it as a reference to the
828           // underlying declaration.
829           if (R.IsDecl && !isa<UnresolvedUsingValueDecl>(Decl))
830             Tok.addModifier(HighlightingModifier::Declaration);
831         }
832       },
833       AST.getHeuristicResolver());
834   // Add highlightings for macro references.
835   auto AddMacro = [&](const MacroOccurrence &M) {
836     auto &T = Builder.addToken(M.Rng, HighlightingKind::Macro);
837     T.addModifier(HighlightingModifier::GlobalScope);
838     if (M.IsDefinition)
839       T.addModifier(HighlightingModifier::Declaration);
840   };
841   for (const auto &SIDToRefs : AST.getMacros().MacroRefs)
842     for (const auto &M : SIDToRefs.second)
843       AddMacro(M);
844   for (const auto &M : AST.getMacros().UnknownMacros)
845     AddMacro(M);
846 
847   return std::move(Builder).collect(AST);
848 }
849 
850 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
851   switch (K) {
852   case HighlightingKind::Variable:
853     return OS << "Variable";
854   case HighlightingKind::LocalVariable:
855     return OS << "LocalVariable";
856   case HighlightingKind::Parameter:
857     return OS << "Parameter";
858   case HighlightingKind::Function:
859     return OS << "Function";
860   case HighlightingKind::Method:
861     return OS << "Method";
862   case HighlightingKind::StaticMethod:
863     return OS << "StaticMethod";
864   case HighlightingKind::Field:
865     return OS << "Field";
866   case HighlightingKind::StaticField:
867     return OS << "StaticField";
868   case HighlightingKind::Class:
869     return OS << "Class";
870   case HighlightingKind::Interface:
871     return OS << "Interface";
872   case HighlightingKind::Enum:
873     return OS << "Enum";
874   case HighlightingKind::EnumConstant:
875     return OS << "EnumConstant";
876   case HighlightingKind::Typedef:
877     return OS << "Typedef";
878   case HighlightingKind::Type:
879     return OS << "Type";
880   case HighlightingKind::Unknown:
881     return OS << "Unknown";
882   case HighlightingKind::Namespace:
883     return OS << "Namespace";
884   case HighlightingKind::TemplateParameter:
885     return OS << "TemplateParameter";
886   case HighlightingKind::Concept:
887     return OS << "Concept";
888   case HighlightingKind::Primitive:
889     return OS << "Primitive";
890   case HighlightingKind::Macro:
891     return OS << "Macro";
892   case HighlightingKind::InactiveCode:
893     return OS << "InactiveCode";
894   }
895   llvm_unreachable("invalid HighlightingKind");
896 }
897 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingModifier K) {
898   switch (K) {
899   case HighlightingModifier::Declaration:
900     return OS << "decl"; // abbrevation for common case
901   default:
902     return OS << toSemanticTokenModifier(K);
903   }
904 }
905 
906 bool operator==(const HighlightingToken &L, const HighlightingToken &R) {
907   return std::tie(L.R, L.Kind, L.Modifiers) ==
908          std::tie(R.R, R.Kind, R.Modifiers);
909 }
910 bool operator<(const HighlightingToken &L, const HighlightingToken &R) {
911   return std::tie(L.R, L.Kind, R.Modifiers) <
912          std::tie(R.R, R.Kind, R.Modifiers);
913 }
914 
915 std::vector<SemanticToken>
916 toSemanticTokens(llvm::ArrayRef<HighlightingToken> Tokens) {
917   assert(std::is_sorted(Tokens.begin(), Tokens.end()));
918   std::vector<SemanticToken> Result;
919   const HighlightingToken *Last = nullptr;
920   for (const HighlightingToken &Tok : Tokens) {
921     Result.emplace_back();
922     SemanticToken &Out = Result.back();
923     // deltaStart/deltaLine are relative if possible.
924     if (Last) {
925       assert(Tok.R.start.line >= Last->R.start.line);
926       Out.deltaLine = Tok.R.start.line - Last->R.start.line;
927       if (Out.deltaLine == 0) {
928         assert(Tok.R.start.character >= Last->R.start.character);
929         Out.deltaStart = Tok.R.start.character - Last->R.start.character;
930       } else {
931         Out.deltaStart = Tok.R.start.character;
932       }
933     } else {
934       Out.deltaLine = Tok.R.start.line;
935       Out.deltaStart = Tok.R.start.character;
936     }
937     assert(Tok.R.end.line == Tok.R.start.line);
938     Out.length = Tok.R.end.character - Tok.R.start.character;
939     Out.tokenType = static_cast<unsigned>(Tok.Kind);
940     Out.tokenModifiers = Tok.Modifiers;
941 
942     Last = &Tok;
943   }
944   return Result;
945 }
946 llvm::StringRef toSemanticTokenType(HighlightingKind Kind) {
947   switch (Kind) {
948   case HighlightingKind::Variable:
949   case HighlightingKind::LocalVariable:
950   case HighlightingKind::StaticField:
951     return "variable";
952   case HighlightingKind::Parameter:
953     return "parameter";
954   case HighlightingKind::Function:
955     return "function";
956   case HighlightingKind::Method:
957     return "method";
958   case HighlightingKind::StaticMethod:
959     // FIXME: better method with static modifier?
960     return "function";
961   case HighlightingKind::Field:
962     return "property";
963   case HighlightingKind::Class:
964     return "class";
965   case HighlightingKind::Interface:
966     return "interface";
967   case HighlightingKind::Enum:
968     return "enum";
969   case HighlightingKind::EnumConstant:
970     return "enumMember";
971   case HighlightingKind::Typedef:
972   case HighlightingKind::Type:
973     return "type";
974   case HighlightingKind::Unknown:
975     return "unknown"; // nonstandard
976   case HighlightingKind::Namespace:
977     return "namespace";
978   case HighlightingKind::TemplateParameter:
979     return "typeParameter";
980   case HighlightingKind::Concept:
981     return "concept"; // nonstandard
982   case HighlightingKind::Primitive:
983     return "type";
984   case HighlightingKind::Macro:
985     return "macro";
986   case HighlightingKind::InactiveCode:
987     return "comment";
988   }
989   llvm_unreachable("unhandled HighlightingKind");
990 }
991 
992 llvm::StringRef toSemanticTokenModifier(HighlightingModifier Modifier) {
993   switch (Modifier) {
994   case HighlightingModifier::Declaration:
995     return "declaration";
996   case HighlightingModifier::Deprecated:
997     return "deprecated";
998   case HighlightingModifier::Readonly:
999     return "readonly";
1000   case HighlightingModifier::Static:
1001     return "static";
1002   case HighlightingModifier::Deduced:
1003     return "deduced"; // nonstandard
1004   case HighlightingModifier::Abstract:
1005     return "abstract";
1006   case HighlightingModifier::Virtual:
1007     return "virtual";
1008   case HighlightingModifier::DependentName:
1009     return "dependentName"; // nonstandard
1010   case HighlightingModifier::DefaultLibrary:
1011     return "defaultLibrary";
1012   case HighlightingModifier::UsedAsMutableReference:
1013     return "usedAsMutableReference"; // nonstandard
1014   case HighlightingModifier::FunctionScope:
1015     return "functionScope"; // nonstandard
1016   case HighlightingModifier::ClassScope:
1017     return "classScope"; // nonstandard
1018   case HighlightingModifier::FileScope:
1019     return "fileScope"; // nonstandard
1020   case HighlightingModifier::GlobalScope:
1021     return "globalScope"; // nonstandard
1022   }
1023   llvm_unreachable("unhandled HighlightingModifier");
1024 }
1025 
1026 std::vector<SemanticTokensEdit>
1027 diffTokens(llvm::ArrayRef<SemanticToken> Old,
1028            llvm::ArrayRef<SemanticToken> New) {
1029   // For now, just replace everything from the first-last modification.
1030   // FIXME: use a real diff instead, this is bad with include-insertion.
1031 
1032   unsigned Offset = 0;
1033   while (!Old.empty() && !New.empty() && Old.front() == New.front()) {
1034     ++Offset;
1035     Old = Old.drop_front();
1036     New = New.drop_front();
1037   }
1038   while (!Old.empty() && !New.empty() && Old.back() == New.back()) {
1039     Old = Old.drop_back();
1040     New = New.drop_back();
1041   }
1042 
1043   if (Old.empty() && New.empty())
1044     return {};
1045   SemanticTokensEdit Edit;
1046   Edit.startToken = Offset;
1047   Edit.deleteTokens = Old.size();
1048   Edit.tokens = New;
1049   return {std::move(Edit)};
1050 }
1051 
1052 } // namespace clangd
1053 } // namespace clang
1054