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