clang-tools  16.0.0git
SemanticHighlighting.cpp
Go to the documentation of this file.
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/ADT/StringRef.h"
34 #include "llvm/Support/Casting.h"
35 #include "llvm/Support/Error.h"
36 #include <algorithm>
37 
38 namespace clang {
39 namespace clangd {
40 namespace {
41 
42 /// Some names are not written in the source code and cannot be highlighted,
43 /// e.g. anonymous classes. This function detects those cases.
44 bool canHighlightName(DeclarationName Name) {
45  switch (Name.getNameKind()) {
46  case DeclarationName::Identifier: {
47  auto *II = Name.getAsIdentifierInfo();
48  return II && !II->getName().empty();
49  }
50  case DeclarationName::CXXConstructorName:
51  case DeclarationName::CXXDestructorName:
52  return true;
53  case DeclarationName::ObjCZeroArgSelector:
54  case DeclarationName::ObjCOneArgSelector:
55  case DeclarationName::ObjCMultiArgSelector:
56  // Multi-arg selectors need special handling, and we handle 0/1 arg
57  // selectors there too.
58  return false;
59  case DeclarationName::CXXConversionFunctionName:
60  case DeclarationName::CXXOperatorName:
61  case DeclarationName::CXXDeductionGuideName:
62  case DeclarationName::CXXLiteralOperatorName:
63  case DeclarationName::CXXUsingDirective:
64  return false;
65  }
66  llvm_unreachable("invalid name kind");
67 }
68 
69 bool isUniqueDefinition(const NamedDecl *Decl) {
70  if (auto *Func = dyn_cast<FunctionDecl>(Decl))
71  return Func->isThisDeclarationADefinition();
72  if (auto *Klass = dyn_cast<CXXRecordDecl>(Decl))
73  return Klass->isThisDeclarationADefinition();
74  if (auto *Iface = dyn_cast<ObjCInterfaceDecl>(Decl))
75  return Iface->isThisDeclarationADefinition();
76  if (auto *Proto = dyn_cast<ObjCProtocolDecl>(Decl))
77  return Proto->isThisDeclarationADefinition();
78  if (auto *Var = dyn_cast<VarDecl>(Decl))
79  return Var->isThisDeclarationADefinition();
80  return isa<TemplateTypeParmDecl>(Decl) ||
81  isa<NonTypeTemplateParmDecl>(Decl) ||
82  isa<TemplateTemplateParmDecl>(Decl) || isa<ObjCCategoryDecl>(Decl) ||
83  isa<ObjCImplDecl>(Decl);
84 }
85 
86 llvm::Optional<HighlightingKind> kindForType(const Type *TP,
87  const HeuristicResolver *Resolver);
88 llvm::Optional<HighlightingKind>
89 kindForDecl(const NamedDecl *D, const HeuristicResolver *Resolver) {
90  if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
91  if (auto *Target = USD->getTargetDecl())
92  D = Target;
93  }
94  if (auto *TD = dyn_cast<TemplateDecl>(D)) {
95  if (auto *Templated = TD->getTemplatedDecl())
96  D = Templated;
97  }
98  if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
99  // We try to highlight typedefs as their underlying type.
100  if (auto K =
101  kindForType(TD->getUnderlyingType().getTypePtrOrNull(), Resolver))
102  return K;
103  // And fallback to a generic kind if this fails.
105  }
106  // We highlight class decls, constructor decls and destructor decls as
107  // `Class` type. The destructor decls are handled in `VisitTagTypeLoc` (we
108  // will visit a TypeLoc where the underlying Type is a CXXRecordDecl).
109  if (auto *RD = llvm::dyn_cast<RecordDecl>(D)) {
110  // We don't want to highlight lambdas like classes.
111  if (RD->isLambda())
112  return llvm::None;
114  }
115  if (isa<ClassTemplateDecl, RecordDecl, CXXConstructorDecl, ObjCInterfaceDecl,
116  ObjCImplementationDecl>(D))
118  if (isa<ObjCProtocolDecl>(D))
120  if (isa<ObjCCategoryDecl>(D))
122  if (auto *MD = dyn_cast<CXXMethodDecl>(D))
123  return MD->isStatic() ? HighlightingKind::StaticMethod
125  if (auto *OMD = dyn_cast<ObjCMethodDecl>(D))
126  return OMD->isClassMethod() ? HighlightingKind::StaticMethod
128  if (isa<FieldDecl, ObjCPropertyDecl>(D))
130  if (isa<EnumDecl>(D))
131  return HighlightingKind::Enum;
132  if (isa<EnumConstantDecl>(D))
134  if (isa<ParmVarDecl>(D))
136  if (auto *VD = dyn_cast<VarDecl>(D)) {
137  if (isa<ImplicitParamDecl>(VD)) // e.g. ObjC Self
138  return llvm::None;
139  return VD->isStaticDataMember()
141  : VD->isLocalVarDecl() ? HighlightingKind::LocalVariable
143  }
144  if (const auto *BD = dyn_cast<BindingDecl>(D))
145  return BD->getDeclContext()->isFunctionOrMethod()
148  if (isa<FunctionDecl>(D))
150  if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D) ||
151  isa<UsingDirectiveDecl>(D))
153  if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
154  isa<NonTypeTemplateParmDecl>(D))
156  if (isa<ConceptDecl>(D))
158  if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(D)) {
159  auto Targets = Resolver->resolveUsingValueDecl(UUVD);
160  if (!Targets.empty()) {
161  return kindForDecl(Targets[0], Resolver);
162  }
164  }
165  return llvm::None;
166 }
167 llvm::Optional<HighlightingKind>
168 kindForType(const Type *TP, const HeuristicResolver *Resolver) {
169  if (!TP)
170  return llvm::None;
171  if (TP->isBuiltinType()) // Builtins are special, they do not have decls.
173  if (auto *TD = dyn_cast<TemplateTypeParmType>(TP))
174  return kindForDecl(TD->getDecl(), Resolver);
175  if (isa<ObjCObjectPointerType>(TP))
177  if (auto *TD = TP->getAsTagDecl())
178  return kindForDecl(TD, Resolver);
179  return llvm::None;
180 }
181 
182 // Whether T is const in a loose sense - is a variable with this type readonly?
183 bool isConst(QualType T) {
184  if (T.isNull())
185  return false;
186  T = T.getNonReferenceType();
187  if (T.isConstQualified())
188  return true;
189  if (const auto *AT = T->getAsArrayTypeUnsafe())
190  return isConst(AT->getElementType());
191  if (isConst(T->getPointeeType()))
192  return true;
193  return false;
194 }
195 
196 // Whether D is const in a loose sense (should it be highlighted as such?)
197 // FIXME: This is separate from whether *a particular usage* can mutate D.
198 // We may want V in V.size() to be readonly even if V is mutable.
199 bool isConst(const Decl *D) {
200  if (llvm::isa<EnumConstantDecl>(D) || llvm::isa<NonTypeTemplateParmDecl>(D))
201  return true;
202  if (llvm::isa<FieldDecl>(D) || llvm::isa<VarDecl>(D) ||
203  llvm::isa<MSPropertyDecl>(D) || llvm::isa<BindingDecl>(D)) {
204  if (isConst(llvm::cast<ValueDecl>(D)->getType()))
205  return true;
206  }
207  if (const auto *OCPD = llvm::dyn_cast<ObjCPropertyDecl>(D)) {
208  if (OCPD->isReadOnly())
209  return true;
210  }
211  if (const auto *MPD = llvm::dyn_cast<MSPropertyDecl>(D)) {
212  if (!MPD->hasSetter())
213  return true;
214  }
215  if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
216  if (CMD->isConst())
217  return true;
218  }
219  return false;
220 }
221 
222 // "Static" means many things in C++, only some get the "static" modifier.
223 //
224 // Meanings that do:
225 // - Members associated with the class rather than the instance.
226 // This is what 'static' most often means across languages.
227 // - static local variables
228 // These are similarly "detached from their context" by the static keyword.
229 // In practice, these are rarely used inside classes, reducing confusion.
230 //
231 // Meanings that don't:
232 // - Namespace-scoped variables, which have static storage class.
233 // This is implicit, so the keyword "static" isn't so strongly associated.
234 // If we want a modifier for these, "global scope" is probably the concept.
235 // - Namespace-scoped variables/functions explicitly marked "static".
236 // There the keyword changes *linkage* , which is a totally different concept.
237 // If we want to model this, "file scope" would be a nice modifier.
238 //
239 // This is confusing, and maybe we should use another name, but because "static"
240 // is a standard LSP modifier, having one with that name has advantages.
241 bool isStatic(const Decl *D) {
242  if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
243  return CMD->isStatic();
244  if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
245  return VD->isStaticDataMember() || VD->isStaticLocal();
246  if (const auto *OPD = llvm::dyn_cast<ObjCPropertyDecl>(D))
247  return OPD->isClassProperty();
248  if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D))
249  return OMD->isClassMethod();
250  return false;
251 }
252 
253 bool isAbstract(const Decl *D) {
254  if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
255  return CMD->isPure();
256  if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(D))
257  return CRD->hasDefinition() && CRD->isAbstract();
258  return false;
259 }
260 
261 bool isVirtual(const Decl *D) {
262  if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
263  return CMD->isVirtual();
264  return false;
265 }
266 
267 bool isDependent(const Decl *D) {
268  if (isa<UnresolvedUsingValueDecl>(D))
269  return true;
270  return false;
271 }
272 
273 /// Returns true if `Decl` is considered to be from a default/system library.
274 /// This currently checks the systemness of the file by include type, although
275 /// different heuristics may be used in the future (e.g. sysroot paths).
276 bool isDefaultLibrary(const Decl *D) {
277  SourceLocation Loc = D->getLocation();
278  if (!Loc.isValid())
279  return false;
280  return D->getASTContext().getSourceManager().isInSystemHeader(Loc);
281 }
282 
283 bool isDefaultLibrary(const Type *T) {
284  if (!T)
285  return false;
286  const Type *Underlying = T->getPointeeOrArrayElementType();
287  if (Underlying->isBuiltinType())
288  return true;
289  if (auto *TD = dyn_cast<TemplateTypeParmType>(Underlying))
290  return isDefaultLibrary(TD->getDecl());
291  if (auto *TD = Underlying->getAsTagDecl())
292  return isDefaultLibrary(TD);
293  return false;
294 }
295 
296 // For a macro usage `DUMP(foo)`, we want:
297 // - DUMP --> "macro"
298 // - foo --> "variable".
299 SourceLocation getHighlightableSpellingToken(SourceLocation L,
300  const SourceManager &SM) {
301  if (L.isFileID())
302  return SM.isWrittenInMainFile(L) ? L : SourceLocation{};
303  // Tokens expanded from the macro body contribute no highlightings.
304  if (!SM.isMacroArgExpansion(L))
305  return {};
306  // Tokens expanded from macro args are potentially highlightable.
307  return getHighlightableSpellingToken(SM.getImmediateSpellingLoc(L), SM);
308 }
309 
310 unsigned evaluateHighlightPriority(const HighlightingToken &Tok) {
311  enum HighlightPriority { Dependent = 0, Resolved = 1 };
312  return (Tok.Modifiers & (1 << uint32_t(HighlightingModifier::DependentName)))
313  ? Dependent
314  : Resolved;
315 }
316 
317 // Sometimes we get multiple tokens at the same location:
318 //
319 // - findExplicitReferences() returns a heuristic result for a dependent name
320 // (e.g. Method) and CollectExtraHighlighting returning a fallback dependent
321 // highlighting (e.g. Unknown+Dependent).
322 // - macro arguments are expanded multiple times and have different roles
323 // - broken code recovery produces several AST nodes at the same location
324 //
325 // We should either resolve these to a single token, or drop them all.
326 // Our heuristics are:
327 //
328 // - token kinds that come with "dependent-name" modifiers are less reliable
329 // (these tend to be vague, like Type or Unknown)
330 // - if we have multiple equally reliable kinds, drop token rather than guess
331 // - take the union of modifiers from all tokens
332 //
333 // In particular, heuristically resolved dependent names get their heuristic
334 // kind, plus the dependent modifier.
335 llvm::Optional<HighlightingToken> resolveConflict(const HighlightingToken &A,
336  const HighlightingToken &B) {
337  unsigned Priority1 = evaluateHighlightPriority(A);
338  unsigned Priority2 = evaluateHighlightPriority(B);
339  if (Priority1 == Priority2 && A.Kind != B.Kind)
340  return llvm::None;
341  auto Result = Priority1 > Priority2 ? A : B;
342  Result.Modifiers = A.Modifiers | B.Modifiers;
343  return Result;
344 }
345 llvm::Optional<HighlightingToken>
346 resolveConflict(ArrayRef<HighlightingToken> Tokens) {
347  if (Tokens.size() == 1)
348  return Tokens[0];
349 
350  assert(Tokens.size() >= 2);
351  Optional<HighlightingToken> Winner = resolveConflict(Tokens[0], Tokens[1]);
352  for (size_t I = 2; Winner && I < Tokens.size(); ++I)
353  Winner = resolveConflict(*Winner, Tokens[I]);
354  return Winner;
355 }
356 
357 /// Consumes source locations and maps them to text ranges for highlightings.
358 class HighlightingsBuilder {
359 public:
360  HighlightingsBuilder(const ParsedAST &AST)
361  : TB(AST.getTokens()), SourceMgr(AST.getSourceManager()),
362  LangOpts(AST.getLangOpts()) {}
363 
364  HighlightingToken &addToken(SourceLocation Loc, HighlightingKind Kind) {
365  auto Range = getRangeForSourceLocation(Loc);
366  if (!Range)
367  return InvalidHighlightingToken;
368 
369  return addToken(*Range, Kind);
370  }
371 
372  HighlightingToken &addToken(Range R, HighlightingKind Kind) {
373  HighlightingToken HT;
374  HT.R = std::move(R);
375  HT.Kind = Kind;
376  Tokens.push_back(std::move(HT));
377  return Tokens.back();
378  }
379 
380  void addExtraModifier(SourceLocation Loc, HighlightingModifier Modifier) {
381  if (auto Range = getRangeForSourceLocation(Loc))
382  ExtraModifiers[*Range].push_back(Modifier);
383  }
384 
385  std::vector<HighlightingToken> collect(ParsedAST &AST) && {
386  // Initializer lists can give duplicates of tokens, therefore all tokens
387  // must be deduplicated.
388  llvm::sort(Tokens);
389  auto Last = std::unique(Tokens.begin(), Tokens.end());
390  Tokens.erase(Last, Tokens.end());
391 
392  // Macros can give tokens that have the same source range but conflicting
393  // kinds. In this case all tokens sharing this source range should be
394  // removed.
395  std::vector<HighlightingToken> NonConflicting;
396  NonConflicting.reserve(Tokens.size());
397  for (ArrayRef<HighlightingToken> TokRef = Tokens; !TokRef.empty();) {
398  ArrayRef<HighlightingToken> Conflicting =
399  TokRef.take_while([&](const HighlightingToken &T) {
400  // TokRef is guaranteed at least one element here because otherwise
401  // this predicate would never fire.
402  return T.R == TokRef.front().R;
403  });
404  if (auto Resolved = resolveConflict(Conflicting)) {
405  // Apply extra collected highlighting modifiers
406  auto Modifiers = ExtraModifiers.find(Resolved->R);
407  if (Modifiers != ExtraModifiers.end()) {
408  for (HighlightingModifier Mod : Modifiers->second) {
409  Resolved->addModifier(Mod);
410  }
411  }
412 
413  NonConflicting.push_back(*Resolved);
414  }
415  // TokRef[Conflicting.size()] is the next token with a different range (or
416  // the end of the Tokens).
417  TokRef = TokRef.drop_front(Conflicting.size());
418  }
419 
420  const auto &SM = AST.getSourceManager();
421  StringRef MainCode = SM.getBufferOrFake(SM.getMainFileID()).getBuffer();
422 
423  // Merge token stream with "inactive line" markers.
424  std::vector<HighlightingToken> WithInactiveLines;
425  auto SortedSkippedRanges = AST.getMacros().SkippedRanges;
426  llvm::sort(SortedSkippedRanges);
427  auto It = NonConflicting.begin();
428  for (const Range &R : SortedSkippedRanges) {
429  // Create one token for each line in the skipped range, so it works
430  // with line-based diffing.
431  assert(R.start.line <= R.end.line);
432  for (int Line = R.start.line; Line <= R.end.line; ++Line) {
433  // If the end of the inactive range is at the beginning
434  // of a line, that line is not inactive.
435  if (Line == R.end.line && R.end.character == 0)
436  continue;
437  // Copy tokens before the inactive line
438  for (; It != NonConflicting.end() && It->R.start.line < Line; ++It)
439  WithInactiveLines.push_back(std::move(*It));
440  // Add a token for the inactive line itself.
441  auto StartOfLine = positionToOffset(MainCode, Position{Line, 0});
442  if (StartOfLine) {
443  StringRef LineText =
444  MainCode.drop_front(*StartOfLine).take_until([](char C) {
445  return C == '\n';
446  });
447  HighlightingToken HT;
448  WithInactiveLines.emplace_back();
449  WithInactiveLines.back().Kind = HighlightingKind::InactiveCode;
450  WithInactiveLines.back().R.start.line = Line;
451  WithInactiveLines.back().R.end.line = Line;
452  WithInactiveLines.back().R.end.character =
453  static_cast<int>(lspLength(LineText));
454  } else {
455  elog("Failed to convert position to offset: {0}",
456  StartOfLine.takeError());
457  }
458 
459  // Skip any other tokens on the inactive line. e.g.
460  // `#ifndef Foo` is considered as part of an inactive region when Foo is
461  // defined, and there is a Foo macro token.
462  // FIXME: we should reduce the scope of the inactive region to not
463  // include the directive itself.
464  while (It != NonConflicting.end() && It->R.start.line == Line)
465  ++It;
466  }
467  }
468  // Copy tokens after the last inactive line
469  for (; It != NonConflicting.end(); ++It)
470  WithInactiveLines.push_back(std::move(*It));
471  return WithInactiveLines;
472  }
473 
474  const HeuristicResolver *getResolver() const { return Resolver; }
475 
476 private:
477  llvm::Optional<Range> getRangeForSourceLocation(SourceLocation Loc) {
478  Loc = getHighlightableSpellingToken(Loc, SourceMgr);
479  if (Loc.isInvalid())
480  return llvm::None;
481 
482  const auto *Tok = TB.spelledTokenAt(Loc);
483  assert(Tok);
484 
485  return halfOpenToRange(SourceMgr,
486  Tok->range(SourceMgr).toCharRange(SourceMgr));
487  }
488 
489  const syntax::TokenBuffer &TB;
490  const SourceManager &SourceMgr;
491  const LangOptions &LangOpts;
492  std::vector<HighlightingToken> Tokens;
493  std::map<Range, llvm::SmallVector<HighlightingModifier, 1>> ExtraModifiers;
494  const HeuristicResolver *Resolver = nullptr;
495  // returned from addToken(InvalidLoc)
496  HighlightingToken InvalidHighlightingToken;
497 };
498 
499 llvm::Optional<HighlightingModifier> scopeModifier(const NamedDecl *D) {
500  const DeclContext *DC = D->getDeclContext();
501  // Injected "Foo" within the class "Foo" has file scope, not class scope.
502  if (auto *R = dyn_cast_or_null<RecordDecl>(D))
503  if (R->isInjectedClassName())
504  DC = DC->getParent();
505  // Lambda captures are considered function scope, not class scope.
506  if (llvm::isa<FieldDecl>(D))
507  if (const auto *RD = llvm::dyn_cast<RecordDecl>(DC))
508  if (RD->isLambda())
510  // Walk up the DeclContext hierarchy until we find something interesting.
511  for (; !DC->isFileContext(); DC = DC->getParent()) {
512  if (DC->isFunctionOrMethod())
514  if (DC->isRecord())
516  }
517  // Some template parameters (e.g. those for variable templates) don't have
518  // meaningful DeclContexts. That doesn't mean they're global!
519  if (DC->isTranslationUnit() && D->isTemplateParameter())
520  return llvm::None;
521  // ExternalLinkage threshold could be tweaked, e.g. module-visible as global.
522  if (D->getLinkageInternal() < ExternalLinkage)
525 }
526 
527 llvm::Optional<HighlightingModifier> scopeModifier(const Type *T) {
528  if (!T)
529  return llvm::None;
530  if (T->isBuiltinType())
532  if (auto *TD = dyn_cast<TemplateTypeParmType>(T))
533  return scopeModifier(TD->getDecl());
534  if (auto *TD = T->getAsTagDecl())
535  return scopeModifier(TD);
536  return llvm::None;
537 }
538 
539 /// Produces highlightings, which are not captured by findExplicitReferences,
540 /// e.g. highlights dependent names and 'auto' as the underlying type.
541 class CollectExtraHighlightings
542  : public RecursiveASTVisitor<CollectExtraHighlightings> {
544 
545 public:
546  CollectExtraHighlightings(HighlightingsBuilder &H) : H(H) {}
547 
548  bool VisitCXXConstructExpr(CXXConstructExpr *E) {
549  highlightMutableReferenceArguments(E->getConstructor(),
550  {E->getArgs(), E->getNumArgs()});
551 
552  return true;
553  }
554 
555  bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
556  if (Init->isMemberInitializer())
557  if (auto *Member = Init->getMember())
558  highlightMutableReferenceArgument(Member->getType(), Init->getInit());
559  return Base::TraverseConstructorInitializer(Init);
560  }
561 
562  bool VisitPredefinedExpr(PredefinedExpr *E) {
563  H.addToken(E->getLocation(), HighlightingKind::LocalVariable)
564  .addModifier(HighlightingModifier::Static)
565  .addModifier(HighlightingModifier::Readonly)
567  return true;
568  }
569 
570  bool VisitCallExpr(CallExpr *E) {
571  // Highlighting parameters passed by non-const reference does not really
572  // make sense for literals...
573  if (isa<UserDefinedLiteral>(E))
574  return true;
575 
576  // FIXME: consider highlighting parameters of some other overloaded
577  // operators as well
578  llvm::ArrayRef<const Expr *> Args = {E->getArgs(), E->getNumArgs()};
579  if (auto *CallOp = dyn_cast<CXXOperatorCallExpr>(E)) {
580  switch (CallOp->getOperator()) {
581  case OO_Call:
582  case OO_Subscript:
583  Args = Args.drop_front(); // Drop object parameter
584  break;
585  default:
586  return true;
587  }
588  }
589 
590  highlightMutableReferenceArguments(
591  dyn_cast_or_null<FunctionDecl>(E->getCalleeDecl()), Args);
592 
593  return true;
594  }
595 
596  void highlightMutableReferenceArgument(QualType T, const Expr *Arg) {
597  if (!Arg)
598  return;
599 
600  // Is this parameter passed by non-const pointer or reference?
601  // FIXME The condition T->idDependentType() could be relaxed a bit,
602  // e.g. std::vector<T>& is dependent but we would want to highlight it
603  bool IsRef = T->isLValueReferenceType();
604  bool IsPtr = T->isPointerType();
605  if ((!IsRef && !IsPtr) || T->getPointeeType().isConstQualified() ||
606  T->isDependentType()) {
607  return;
608  }
609 
610  llvm::Optional<SourceLocation> Location;
611 
612  // FIXME Add "unwrapping" for ArraySubscriptExpr,
613  // e.g. highlight `a` in `a[i]`
614  // FIXME Handle dependent expression types
615  if (auto *IC = dyn_cast<ImplicitCastExpr>(Arg))
616  Arg = IC->getSubExprAsWritten();
617  if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
618  if (UO->getOpcode() == UO_AddrOf)
619  Arg = UO->getSubExpr();
620  }
621  if (auto *DR = dyn_cast<DeclRefExpr>(Arg))
622  Location = DR->getLocation();
623  else if (auto *M = dyn_cast<MemberExpr>(Arg))
624  Location = M->getMemberLoc();
625 
626  if (Location)
627  H.addExtraModifier(*Location,
630  }
631 
632  void
633  highlightMutableReferenceArguments(const FunctionDecl *FD,
634  llvm::ArrayRef<const Expr *const> Args) {
635  if (!FD)
636  return;
637 
638  if (auto *ProtoType = FD->getType()->getAs<FunctionProtoType>()) {
639  // Iterate over the types of the function parameters.
640  // If any of them are non-const reference paramteres, add it as a
641  // highlighting modifier to the corresponding expression
642  for (size_t I = 0;
643  I < std::min(size_t(ProtoType->getNumParams()), Args.size()); ++I) {
644  highlightMutableReferenceArgument(ProtoType->getParamType(I), Args[I]);
645  }
646  }
647  }
648 
649  bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) {
650  if (auto K = kindForType(L.getTypePtr(), H.getResolver())) {
651  auto &Tok = H.addToken(L.getBeginLoc(), *K)
652  .addModifier(HighlightingModifier::Deduced);
653  if (auto Mod = scopeModifier(L.getTypePtr()))
654  Tok.addModifier(*Mod);
655  if (isDefaultLibrary(L.getTypePtr()))
656  Tok.addModifier(HighlightingModifier::DefaultLibrary);
657  }
658  return true;
659  }
660 
661  bool VisitCXXDestructorDecl(CXXDestructorDecl *D) {
662  if (auto *TI = D->getNameInfo().getNamedTypeInfo()) {
663  SourceLocation Loc = TI->getTypeLoc().getBeginLoc();
665  H.addExtraModifier(Loc, HighlightingModifier::Declaration);
666  if (D->isThisDeclarationADefinition())
667  H.addExtraModifier(Loc, HighlightingModifier::Definition);
668  }
669  return true;
670  }
671 
672  bool VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) {
673  // getMethodDecl can return nullptr with member pointers, e.g.
674  // `(foo.*pointer_to_member_fun)(arg);`
675  if (isa_and_present<CXXDestructorDecl>(CE->getMethodDecl())) {
676  if (auto *ME = dyn_cast<MemberExpr>(CE->getCallee())) {
677  if (auto *TI = ME->getMemberNameInfo().getNamedTypeInfo()) {
678  H.addExtraModifier(TI->getTypeLoc().getBeginLoc(),
680  }
681  }
682  }
683  return true;
684  }
685 
686  bool VisitDeclaratorDecl(DeclaratorDecl *D) {
687  auto *AT = D->getType()->getContainedAutoType();
688  if (!AT)
689  return true;
690  auto K =
691  kindForType(AT->getDeducedType().getTypePtrOrNull(), H.getResolver());
692  if (!K)
693  return true;
694  SourceLocation StartLoc = D->getTypeSpecStartLoc();
695  // The AutoType may not have a corresponding token, e.g. in the case of
696  // init-captures. In this case, StartLoc overlaps with the location
697  // of the decl itself, and producing a token for the type here would result
698  // in both it and the token for the decl being dropped due to conflict.
699  if (StartLoc == D->getLocation())
700  return true;
701  auto &Tok =
702  H.addToken(StartLoc, *K).addModifier(HighlightingModifier::Deduced);
703  const Type *Deduced = AT->getDeducedType().getTypePtrOrNull();
704  if (auto Mod = scopeModifier(Deduced))
705  Tok.addModifier(*Mod);
706  if (isDefaultLibrary(Deduced))
707  Tok.addModifier(HighlightingModifier::DefaultLibrary);
708  return true;
709  }
710 
711  // We handle objective-C selectors specially, because one reference can
712  // cover several non-contiguous tokens.
713  void highlightObjCSelector(const ArrayRef<SourceLocation> &Locs, bool Decl,
714  bool Def, bool Class, bool DefaultLibrary) {
717  for (SourceLocation Part : Locs) {
718  auto &Tok =
719  H.addToken(Part, Kind).addModifier(HighlightingModifier::ClassScope);
720  if (Decl)
721  Tok.addModifier(HighlightingModifier::Declaration);
722  if (Def)
723  Tok.addModifier(HighlightingModifier::Definition);
724  if (Class)
725  Tok.addModifier(HighlightingModifier::Static);
726  if (DefaultLibrary)
727  Tok.addModifier(HighlightingModifier::DefaultLibrary);
728  }
729  }
730 
731  bool VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
732  llvm::SmallVector<SourceLocation> Locs;
733  OMD->getSelectorLocs(Locs);
734  highlightObjCSelector(Locs, /*Decl=*/true,
735  OMD->isThisDeclarationADefinition(),
736  OMD->isClassMethod(), isDefaultLibrary(OMD));
737  return true;
738  }
739 
740  bool VisitObjCMessageExpr(ObjCMessageExpr *OME) {
741  llvm::SmallVector<SourceLocation> Locs;
742  OME->getSelectorLocs(Locs);
743  bool DefaultLibrary = false;
744  if (ObjCMethodDecl *OMD = OME->getMethodDecl())
745  DefaultLibrary = isDefaultLibrary(OMD);
746  highlightObjCSelector(Locs, /*Decl=*/false, /*Def=*/false,
747  OME->isClassMessage(), DefaultLibrary);
748  return true;
749  }
750 
751  // Objective-C allows you to use property syntax `self.prop` as sugar for
752  // `[self prop]` and `[self setProp:]` when there's no explicit `@property`
753  // for `prop` as well as for class properties. We treat this like a property
754  // even though semantically it's equivalent to a method expression.
755  void highlightObjCImplicitPropertyRef(const ObjCMethodDecl *OMD,
756  SourceLocation Loc) {
757  auto &Tok = H.addToken(Loc, HighlightingKind::Field)
758  .addModifier(HighlightingModifier::ClassScope);
759  if (OMD->isClassMethod())
760  Tok.addModifier(HighlightingModifier::Static);
761  if (isDefaultLibrary(OMD))
762  Tok.addModifier(HighlightingModifier::DefaultLibrary);
763  }
764 
765  bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *OPRE) {
766  // We need to handle implicit properties here since they will appear to
767  // reference `ObjCMethodDecl` via an implicit `ObjCMessageExpr`, so normal
768  // highlighting will not work.
769  if (!OPRE->isImplicitProperty())
770  return true;
771  // A single property expr can reference both a getter and setter, but we can
772  // only provide a single semantic token, so prefer the getter. In most cases
773  // the end result should be the same, although it's technically possible
774  // that the user defines a setter for a system SDK.
775  if (OPRE->isMessagingGetter()) {
776  highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertyGetter(),
777  OPRE->getLocation());
778  return true;
779  }
780  if (OPRE->isMessagingSetter()) {
781  highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertySetter(),
782  OPRE->getLocation());
783  }
784  return true;
785  }
786 
787  bool VisitOverloadExpr(OverloadExpr *E) {
788  if (!E->decls().empty())
789  return true; // handled by findExplicitReferences.
790  auto &Tok = H.addToken(E->getNameLoc(), HighlightingKind::Unknown)
792  if (llvm::isa<UnresolvedMemberExpr>(E))
793  Tok.addModifier(HighlightingModifier::ClassScope);
794  // other case is UnresolvedLookupExpr, scope is unknown.
795  return true;
796  }
797 
798  bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
799  H.addToken(E->getMemberNameInfo().getLoc(), HighlightingKind::Unknown)
801  .addModifier(HighlightingModifier::ClassScope);
802  return true;
803  }
804 
805  bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
806  H.addToken(E->getNameInfo().getLoc(), HighlightingKind::Unknown)
808  .addModifier(HighlightingModifier::ClassScope);
809  return true;
810  }
811 
812  bool VisitAttr(Attr *A) {
813  switch (A->getKind()) {
814  case attr::Override:
815  case attr::Final:
816  H.addToken(A->getLocation(), HighlightingKind::Modifier);
817  break;
818  default:
819  break;
820  }
821  return true;
822  }
823 
824  bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
825  H.addToken(L.getNameLoc(), HighlightingKind::Type)
827  .addModifier(HighlightingModifier::ClassScope);
828  return true;
829  }
830 
831  bool VisitDependentTemplateSpecializationTypeLoc(
832  DependentTemplateSpecializationTypeLoc L) {
833  H.addToken(L.getTemplateNameLoc(), HighlightingKind::Type)
835  .addModifier(HighlightingModifier::ClassScope);
836  return true;
837  }
838 
839  bool TraverseTemplateArgumentLoc(TemplateArgumentLoc L) {
840  // Handle template template arguments only (other arguments are handled by
841  // their Expr, TypeLoc etc values).
842  if (L.getArgument().getKind() != TemplateArgument::Template &&
843  L.getArgument().getKind() != TemplateArgument::TemplateExpansion)
844  return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
845 
846  TemplateName N = L.getArgument().getAsTemplateOrTemplatePattern();
847  switch (N.getKind()) {
848  case TemplateName::OverloadedTemplate:
849  // Template template params must always be class templates.
850  // Don't bother to try to work out the scope here.
851  H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class);
852  break;
853  case TemplateName::DependentTemplate:
854  case TemplateName::AssumedTemplate:
855  H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class)
857  break;
858  case TemplateName::Template:
859  case TemplateName::QualifiedTemplate:
860  case TemplateName::SubstTemplateTemplateParm:
861  case TemplateName::SubstTemplateTemplateParmPack:
862  case TemplateName::UsingTemplate:
863  // Names that could be resolved to a TemplateDecl are handled elsewhere.
864  break;
865  }
866  return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
867  }
868 
869  // findExplicitReferences will walk nested-name-specifiers and
870  // find anything that can be resolved to a Decl. However, non-leaf
871  // components of nested-name-specifiers which are dependent names
872  // (kind "Identifier") cannot be resolved to a decl, so we visit
873  // them here.
874  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) {
875  if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) {
876  if (NNS->getKind() == NestedNameSpecifier::Identifier)
877  H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type)
879  .addModifier(HighlightingModifier::ClassScope);
880  }
881  return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q);
882  }
883 
884 private:
885  HighlightingsBuilder &H;
886 };
887 } // namespace
888 
889 std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) {
890  auto &C = AST.getASTContext();
891  // Add highlightings for AST nodes.
892  HighlightingsBuilder Builder(AST);
893  // Highlight 'decltype' and 'auto' as their underlying types.
894  CollectExtraHighlightings(Builder).TraverseAST(C);
895  // Highlight all decls and references coming from the AST.
897  C,
898  [&](ReferenceLoc R) {
899  for (const NamedDecl *Decl : R.Targets) {
900  if (!canHighlightName(Decl->getDeclName()))
901  continue;
902  auto Kind = kindForDecl(Decl, AST.getHeuristicResolver());
903  if (!Kind)
904  continue;
905  auto &Tok = Builder.addToken(R.NameLoc, *Kind);
906 
907  // The attribute tests don't want to look at the template.
908  if (auto *TD = dyn_cast<TemplateDecl>(Decl)) {
909  if (auto *Templated = TD->getTemplatedDecl())
910  Decl = Templated;
911  }
912  if (auto Mod = scopeModifier(Decl))
913  Tok.addModifier(*Mod);
914  if (isConst(Decl))
915  Tok.addModifier(HighlightingModifier::Readonly);
916  if (isStatic(Decl))
917  Tok.addModifier(HighlightingModifier::Static);
918  if (isAbstract(Decl))
919  Tok.addModifier(HighlightingModifier::Abstract);
920  if (isVirtual(Decl))
921  Tok.addModifier(HighlightingModifier::Virtual);
922  if (isDependent(Decl))
923  Tok.addModifier(HighlightingModifier::DependentName);
924  if (isDefaultLibrary(Decl))
925  Tok.addModifier(HighlightingModifier::DefaultLibrary);
926  if (Decl->isDeprecated())
927  Tok.addModifier(HighlightingModifier::Deprecated);
928  if (isa<CXXConstructorDecl>(Decl))
930  if (R.IsDecl) {
931  // Do not treat an UnresolvedUsingValueDecl as a declaration.
932  // It's more common to think of it as a reference to the
933  // underlying declaration.
934  if (!isa<UnresolvedUsingValueDecl>(Decl))
935  Tok.addModifier(HighlightingModifier::Declaration);
936  if (isUniqueDefinition(Decl))
937  Tok.addModifier(HighlightingModifier::Definition);
938  }
939  }
940  },
941  AST.getHeuristicResolver());
942  // Add highlightings for macro references.
943  auto AddMacro = [&](const MacroOccurrence &M) {
944  auto &T = Builder.addToken(M.Rng, HighlightingKind::Macro);
945  T.addModifier(HighlightingModifier::GlobalScope);
946  if (M.IsDefinition)
947  T.addModifier(HighlightingModifier::Declaration);
948  };
949  for (const auto &SIDToRefs : AST.getMacros().MacroRefs)
950  for (const auto &M : SIDToRefs.second)
951  AddMacro(M);
952  for (const auto &M : AST.getMacros().UnknownMacros)
953  AddMacro(M);
954 
955  return std::move(Builder).collect(AST);
956 }
957 
958 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
959  switch (K) {
960  case HighlightingKind::Variable:
961  return OS << "Variable";
962  case HighlightingKind::LocalVariable:
963  return OS << "LocalVariable";
964  case HighlightingKind::Parameter:
965  return OS << "Parameter";
966  case HighlightingKind::Function:
967  return OS << "Function";
968  case HighlightingKind::Method:
969  return OS << "Method";
970  case HighlightingKind::StaticMethod:
971  return OS << "StaticMethod";
973  return OS << "Field";
974  case HighlightingKind::StaticField:
975  return OS << "StaticField";
976  case HighlightingKind::Class:
977  return OS << "Class";
978  case HighlightingKind::Interface:
979  return OS << "Interface";
980  case HighlightingKind::Enum:
981  return OS << "Enum";
982  case HighlightingKind::EnumConstant:
983  return OS << "EnumConstant";
984  case HighlightingKind::Typedef:
985  return OS << "Typedef";
987  return OS << "Type";
989  return OS << "Unknown";
990  case HighlightingKind::Namespace:
991  return OS << "Namespace";
992  case HighlightingKind::TemplateParameter:
993  return OS << "TemplateParameter";
994  case HighlightingKind::Concept:
995  return OS << "Concept";
996  case HighlightingKind::Primitive:
997  return OS << "Primitive";
998  case HighlightingKind::Macro:
999  return OS << "Macro";
1000  case HighlightingKind::Modifier:
1001  return OS << "Modifier";
1002  case HighlightingKind::InactiveCode:
1003  return OS << "InactiveCode";
1004  }
1005  llvm_unreachable("invalid HighlightingKind");
1006 }
1007 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingModifier K) {
1008  switch (K) {
1009  case HighlightingModifier::Declaration:
1010  return OS << "decl"; // abbreviation for common case
1011  case HighlightingModifier::Definition:
1012  return OS << "def"; // abbrevation for common case
1013  case HighlightingModifier::ConstructorOrDestructor:
1014  return OS << "constrDestr";
1015  default:
1016  return OS << toSemanticTokenModifier(K);
1017  }
1018 }
1019 
1021  return std::tie(L.R, L.Kind, L.Modifiers) ==
1022  std::tie(R.R, R.Kind, R.Modifiers);
1023 }
1025  return std::tie(L.R, L.Kind, L.Modifiers) <
1026  std::tie(R.R, R.Kind, R.Modifiers);
1027 }
1028 
1029 std::vector<SemanticToken>
1030 toSemanticTokens(llvm::ArrayRef<HighlightingToken> Tokens,
1031  llvm::StringRef Code) {
1032  assert(llvm::is_sorted(Tokens));
1033  std::vector<SemanticToken> Result;
1034  // In case we split a HighlightingToken into multiple tokens (e.g. because it
1035  // was spanning multiple lines), this tracks the last one. This prevents
1036  // having a copy all the time.
1037  HighlightingToken Scratch;
1038  const HighlightingToken *Last = nullptr;
1039  for (const HighlightingToken &Tok : Tokens) {
1040  Result.emplace_back();
1041  SemanticToken *Out = &Result.back();
1042  // deltaStart/deltaLine are relative if possible.
1043  if (Last) {
1044  assert(Tok.R.start.line >= Last->R.end.line);
1045  Out->deltaLine = Tok.R.start.line - Last->R.end.line;
1046  if (Out->deltaLine == 0) {
1047  assert(Tok.R.start.character >= Last->R.start.character);
1048  Out->deltaStart = Tok.R.start.character - Last->R.start.character;
1049  } else {
1050  Out->deltaStart = Tok.R.start.character;
1051  }
1052  } else {
1053  Out->deltaLine = Tok.R.start.line;
1054  Out->deltaStart = Tok.R.start.character;
1055  }
1056  Out->tokenType = static_cast<unsigned>(Tok.Kind);
1057  Out->tokenModifiers = Tok.Modifiers;
1058  Last = &Tok;
1059 
1060  if (Tok.R.end.line == Tok.R.start.line) {
1061  Out->length = Tok.R.end.character - Tok.R.start.character;
1062  } else {
1063  // If the token spans a line break, split it into multiple pieces for each
1064  // line.
1065  // This is slow, but multiline tokens are rare.
1066  // FIXME: There's a client capability for supporting multiline tokens,
1067  // respect that.
1068  auto TokStartOffset = llvm::cantFail(positionToOffset(Code, Tok.R.start));
1069  // Note that the loop doesn't cover the last line, which has a special
1070  // length.
1071  for (int I = Tok.R.start.line; I < Tok.R.end.line; ++I) {
1072  auto LineEnd = Code.find('\n', TokStartOffset);
1073  assert(LineEnd != Code.npos);
1074  Out->length = LineEnd - TokStartOffset;
1075  // Token continues on next line, right after the line break.
1076  TokStartOffset = LineEnd + 1;
1077  Result.emplace_back();
1078  Out = &Result.back();
1079  *Out = Result[Result.size() - 2];
1080  // New token starts at the first column of the next line.
1081  Out->deltaLine = 1;
1082  Out->deltaStart = 0;
1083  }
1084  // This is the token on last line.
1085  Out->length = Tok.R.end.character;
1086  // Update the start location for last token, as that's used in the
1087  // relative delta calculation for following tokens.
1088  Scratch = *Last;
1089  Scratch.R.start.line = Tok.R.end.line;
1090  Scratch.R.start.character = 0;
1091  Last = &Scratch;
1092  }
1093  }
1094  return Result;
1095 }
1097  switch (Kind) {
1098  case HighlightingKind::Variable:
1099  case HighlightingKind::LocalVariable:
1100  case HighlightingKind::StaticField:
1101  return "variable";
1102  case HighlightingKind::Parameter:
1103  return "parameter";
1104  case HighlightingKind::Function:
1105  return "function";
1106  case HighlightingKind::Method:
1107  return "method";
1108  case HighlightingKind::StaticMethod:
1109  // FIXME: better method with static modifier?
1110  return "function";
1112  return "property";
1113  case HighlightingKind::Class:
1114  return "class";
1115  case HighlightingKind::Interface:
1116  return "interface";
1117  case HighlightingKind::Enum:
1118  return "enum";
1119  case HighlightingKind::EnumConstant:
1120  return "enumMember";
1121  case HighlightingKind::Typedef:
1123  return "type";
1125  return "unknown"; // nonstandard
1126  case HighlightingKind::Namespace:
1127  return "namespace";
1128  case HighlightingKind::TemplateParameter:
1129  return "typeParameter";
1130  case HighlightingKind::Concept:
1131  return "concept"; // nonstandard
1132  case HighlightingKind::Primitive:
1133  return "type";
1134  case HighlightingKind::Macro:
1135  return "macro";
1136  case HighlightingKind::Modifier:
1137  return "modifier";
1138  case HighlightingKind::InactiveCode:
1139  return "comment";
1140  }
1141  llvm_unreachable("unhandled HighlightingKind");
1142 }
1143 
1145  switch (Modifier) {
1146  case HighlightingModifier::Declaration:
1147  return "declaration";
1148  case HighlightingModifier::Definition:
1149  return "definition";
1151  return "deprecated";
1152  case HighlightingModifier::Readonly:
1153  return "readonly";
1155  return "static";
1156  case HighlightingModifier::Deduced:
1157  return "deduced"; // nonstandard
1158  case HighlightingModifier::Abstract:
1159  return "abstract";
1160  case HighlightingModifier::Virtual:
1161  return "virtual";
1162  case HighlightingModifier::DependentName:
1163  return "dependentName"; // nonstandard
1164  case HighlightingModifier::DefaultLibrary:
1165  return "defaultLibrary";
1166  case HighlightingModifier::UsedAsMutableReference:
1167  return "usedAsMutableReference"; // nonstandard
1168  case HighlightingModifier::UsedAsMutablePointer:
1169  return "usedAsMutablePointer"; // nonstandard
1170  case HighlightingModifier::ConstructorOrDestructor:
1171  return "constructorOrDestructor"; // nonstandard
1172  case HighlightingModifier::FunctionScope:
1173  return "functionScope"; // nonstandard
1174  case HighlightingModifier::ClassScope:
1175  return "classScope"; // nonstandard
1176  case HighlightingModifier::FileScope:
1177  return "fileScope"; // nonstandard
1178  case HighlightingModifier::GlobalScope:
1179  return "globalScope"; // nonstandard
1180  }
1181  llvm_unreachable("unhandled HighlightingModifier");
1182 }
1183 
1184 std::vector<SemanticTokensEdit>
1185 diffTokens(llvm::ArrayRef<SemanticToken> Old,
1186  llvm::ArrayRef<SemanticToken> New) {
1187  // For now, just replace everything from the first-last modification.
1188  // FIXME: use a real diff instead, this is bad with include-insertion.
1189 
1190  unsigned Offset = 0;
1191  while (!Old.empty() && !New.empty() && Old.front() == New.front()) {
1192  ++Offset;
1193  Old = Old.drop_front();
1194  New = New.drop_front();
1195  }
1196  while (!Old.empty() && !New.empty() && Old.back() == New.back()) {
1197  Old = Old.drop_back();
1198  New = New.drop_back();
1199  }
1200 
1201  if (Old.empty() && New.empty())
1202  return {};
1204  Edit.startToken = Offset;
1205  Edit.deleteTokens = Old.size();
1206  Edit.tokens = New;
1207  return {std::move(Edit)};
1208 }
1209 
1210 } // namespace clangd
1211 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:39
clang::clangd::HighlightingModifier::FunctionScope
@ FunctionScope
Loc
SourceLocation Loc
Definition: KernelNameRestrictionCheck.cpp:45
clang::clangd::HighlightingModifier::FileScope
@ FileScope
Static
bool Static
Definition: ExtractFunction.cpp:368
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:85
clang::clangd::HighlightingKind::Modifier
@ Modifier
clang::clangd::HighlightingModifier::UsedAsMutablePointer
@ UsedAsMutablePointer
RecursiveASTVisitor
clang::clangd::HighlightingModifier
HighlightingModifier
Definition: SemanticHighlighting.h:63
clang::clangd::Edit
A set of edits generated for a single file.
Definition: SourceCode.h:184
clang::clangd::HighlightingToken::Modifiers
uint32_t Modifiers
Definition: SemanticHighlighting.h:92
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::clangd::toSemanticTokens
std::vector< SemanticToken > toSemanticTokens(llvm::ArrayRef< HighlightingToken > Tokens, llvm::StringRef Code)
Definition: SemanticHighlighting.cpp:1030
clang::clangd::HighlightingKind::Primitive
@ Primitive
Location
Definition: Modularize.cpp:381
clang::doc::MD
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
clang::clangd::toSemanticTokenModifier
llvm::StringRef toSemanticTokenModifier(HighlightingModifier Modifier)
Definition: SemanticHighlighting.cpp:1144
clang::clangd::HighlightingModifier::Deduced
@ Deduced
clang::clangd::ParsedAST::getASTContext
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Definition: ParsedAST.cpp:700
clang::clangd::SemanticTokensEdit
Describes a replacement of a contiguous range of semanticTokens.
Definition: Protocol.h:1704
clang::clangd::lspLength
size_t lspLength(llvm::StringRef Code)
Definition: SourceCode.cpp:148
clang::clangd::HighlightingToken::R
Range R
Definition: SemanticHighlighting.h:93
Kind
BindArgumentKind Kind
Definition: AvoidBindCheck.cpp:59
clang::clangd::Range::start
Position start
The range's start position.
Definition: Protocol.h:187
clang::clangd::HighlightingKind
HighlightingKind
Definition: SemanticHighlighting.h:31
clang::clangd::HighlightingKind::Typedef
@ Typedef
clang::clangd::MainFileMacros::MacroRefs
llvm::DenseMap< SymbolID, std::vector< MacroOccurrence > > MacroRefs
Definition: CollectMacros.h:31
clang::clangd::HighlightingToken::Kind
HighlightingKind Kind
Definition: SemanticHighlighting.h:91
SourceMgr
llvm::SourceMgr * SourceMgr
Definition: ConfigCompile.cpp:101
clang::clangd::HighlightingKind::TemplateParameter
@ TemplateParameter
clang::clangd::operator<
bool operator<(const HighlightingToken &L, const HighlightingToken &R)
Definition: SemanticHighlighting.cpp:1024
FindTarget.h
clang::clangd::HighlightingModifier::Virtual
@ Virtual
clang::clangd::HighlightingKind::Macro
@ Macro
clang::clangd::Position::line
int line
Line position in a document (zero-based).
Definition: Protocol.h:158
clang::clangd::HighlightingKind::Variable
@ Variable
clang::clangd::HighlightingKind::InactiveCode
@ InactiveCode
Protocol.h
M
const google::protobuf::Message & M
Definition: Server.cpp:309
Offset
size_t Offset
Definition: CodeComplete.cpp:1213
ns1::ns2::A
@ A
Definition: CategoricalFeature.h:3
clang::clangd::halfOpenToRange
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
Definition: SourceCode.cpp:467
Code
std::string Code
Definition: FindTargetTests.cpp:67
ns1::ns2::D
@ D
Definition: CategoricalFeature.h:3
clang::clangd::HighlightingKind::Function
@ Function
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
clang::clangd::Unknown
@ Unknown
Definition: FuzzyMatch.h:56
Line
int Line
Definition: PreprocessorTracker.cpp:514
clang::clangd::SemanticToken
Specifies a single semantic token in the document.
Definition: Protocol.h:1656
clang::clangd::diffTokens
std::vector< SemanticTokensEdit > diffTokens(llvm::ArrayRef< SemanticToken > Old, llvm::ArrayRef< SemanticToken > New)
Definition: SemanticHighlighting.cpp:1185
clang::clangd::HighlightingKind::Unknown
@ Unknown
Builder
CodeCompletionBuilder Builder
Definition: CodeCompletionStringsTests.cpp:36
Logger.h
Args
llvm::json::Object Args
Definition: Trace.cpp:138
clang::clangd::positionToOffset
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:172
clang::clangd::HighlightingKind::Namespace
@ Namespace
clang::clangd::HighlightingKind::Type
@ Type
clang::clangd::HighlightingKind::Concept
@ Concept
clang::clangd::HighlightingKind::LocalVariable
@ LocalVariable
clang::clangd::HighlightingModifier::Deprecated
@ Deprecated
clang::clangd::Position::character
int character
Character offset on a line in a document (zero-based).
Definition: Protocol.h:163
clang::clangd::HeuristicResolver::resolveUsingValueDecl
std::vector< const NamedDecl * > resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const
Definition: HeuristicResolver.cpp:164
clang::clangd::Range::end
Position end
The range's end position.
Definition: Protocol.h:190
clang::clangd::HighlightingModifier::Abstract
@ Abstract
clang::clangd::HighlightingModifier::GlobalScope
@ GlobalScope
Name
Token Name
Definition: MacroToEnumCheck.cpp:89
clang::clangd::ParsedAST::getHeuristicResolver
const HeuristicResolver * getHeuristicResolver() const
Definition: ParsedAST.h:119
clang::clangd::DeclRelation::Underlying
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
clang::clangd::HighlightingKind::Enum
@ Enum
clang::clangd::getSemanticHighlightings
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST)
Definition: SemanticHighlighting.cpp:889
clang::clangd::HighlightingKind::Method
@ Method
clang::clangd::Deprecated
@ Deprecated
Deprecated or obsolete code.
Definition: Protocol.h:843
SourceCode.h
HeuristicResolver.h
clang::clangd::operator==
bool operator==(const HighlightingToken &L, const HighlightingToken &R)
Definition: SemanticHighlighting.cpp:1020
clang::clangd::HighlightingModifier::Static
@ Static
clang::clangd::HighlightingKind::Parameter
@ Parameter
clang::clangd::ReferenceLoc
Information about a reference written in the source code, independent of the actual AST node that thi...
Definition: FindTarget.h:126
CE
CaptureExpr CE
Definition: AvoidBindCheck.cpp:67
clang::clangd::HighlightingModifier::ConstructorOrDestructor
@ ConstructorOrDestructor
clang::clangd::HighlightingToken
Definition: SemanticHighlighting.h:90
clang::clangd::HighlightingKind::StaticMethod
@ StaticMethod
clang::clangd::HighlightingModifier::Definition
@ Definition
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::clangd::toSemanticTokenType
llvm::StringRef toSemanticTokenType(HighlightingKind Kind)
Definition: SemanticHighlighting.cpp:1096
SemanticHighlighting.h
clang::clangd::HighlightingModifier::DefaultLibrary
@ DefaultLibrary
if
if(CLANG_PLUGIN_SUPPORT) export_executable_symbols_for_plugins(clang-tidy) endif() install(PROGRAMS clang-tidy-diff.py DESTINATION "$
Definition: clang-tidy/tool/CMakeLists.txt:59
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:160
clang::clangd::HighlightingKind::Interface
@ Interface
clang::clangd::HighlightingKind::StaticField
@ StaticField
LangOpts
const LangOptions * LangOpts
Definition: ExtractFunction.cpp:375
clang::clangd::operator<<
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, HighlightingModifier K)
Definition: SemanticHighlighting.cpp:1007
clang::clangd::ReferenceLoc::IsDecl
bool IsDecl
True if the reference is a declaration or definition;.
Definition: FindTarget.h:132
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ParsedAST.h:46
clang::clangd::HighlightingKind::EnumConstant
@ EnumConstant
Field
const FieldDecl * Field
Definition: MemberwiseConstructor.cpp:260
clang::clangd::MainFileMacros::UnknownMacros
std::vector< MacroOccurrence > UnknownMacros
Definition: CollectMacros.h:35
ns1::ns2::B
@ B
Definition: CategoricalFeature.h:3
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:99
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:61
clang::clangd::findExplicitReferences
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
Definition: FindTarget.cpp:1125
clang::clangd::HighlightingKind::Field
@ Field
clang::clangd::HighlightingKind::Class
@ Class
clang::clangd::ReferenceLoc::Targets
llvm::SmallVector< const NamedDecl *, 1 > Targets
A list of targets referenced by this name.
Definition: FindTarget.h:138
clang::clangd::HighlightingModifier::Readonly
@ Readonly
K
Kind K
Definition: Rename.cpp:454
clang::clangd::HighlightingModifier::DependentName
@ DependentName
clang::clangd::HighlightingModifier::UsedAsMutableReference
@ UsedAsMutableReference
clang::clangd::HighlightingModifier::ClassScope
@ ClassScope
ParsedAST.h
clang::clangd::HighlightingModifier::Declaration
@ Declaration
clang::clangd::ParsedAST::getMacros
const MainFileMacros & getMacros() const
Gets all macro references (definition, expansions) present in the main file, including those in the p...
Definition: ParsedAST.cpp:722