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/Sema/HeuristicResolver.h"
30#include "clang/Tooling/Syntax/Tokens.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/StringRef.h"
33#include "llvm/Support/Casting.h"
34#include "llvm/Support/Error.h"
43llvm::Expected<Position> endOfLine(llvm::StringRef Code,
int Line) {
46 return StartOfLine.takeError();
47 StringRef LineText = Code.drop_front(*StartOfLine).take_until([](
char C) {
55bool canHighlightName(DeclarationName Name) {
56 switch (Name.getNameKind()) {
57 case DeclarationName::Identifier: {
58 auto *II = Name.getAsIdentifierInfo();
59 return II && !II->getName().empty();
61 case DeclarationName::CXXConstructorName:
62 case DeclarationName::CXXDestructorName:
64 case DeclarationName::ObjCZeroArgSelector:
65 case DeclarationName::ObjCOneArgSelector:
66 case DeclarationName::ObjCMultiArgSelector:
70 case DeclarationName::CXXConversionFunctionName:
71 case DeclarationName::CXXOperatorName:
72 case DeclarationName::CXXDeductionGuideName:
73 case DeclarationName::CXXLiteralOperatorName:
74 case DeclarationName::CXXUsingDirective:
77 llvm_unreachable(
"invalid name kind");
80bool isUniqueDefinition(
const NamedDecl *Decl) {
81 if (
auto *Func = dyn_cast<FunctionDecl>(Decl))
82 return Func->isThisDeclarationADefinition();
83 if (
auto *Klass = dyn_cast<CXXRecordDecl>(Decl))
84 return Klass->isThisDeclarationADefinition();
85 if (
auto *Iface = dyn_cast<ObjCInterfaceDecl>(Decl))
86 return Iface->isThisDeclarationADefinition();
87 if (
auto *Proto = dyn_cast<ObjCProtocolDecl>(Decl))
88 return Proto->isThisDeclarationADefinition();
89 if (
auto *Var = dyn_cast<VarDecl>(Decl))
90 return Var->isThisDeclarationADefinition();
91 return isa<TemplateTypeParmDecl>(Decl) ||
92 isa<NonTypeTemplateParmDecl>(Decl) ||
93 isa<TemplateTemplateParmDecl>(Decl) || isa<ObjCCategoryDecl>(Decl) ||
94 isa<ObjCImplDecl>(Decl);
97std::optional<HighlightingKind> kindForType(
const Type *TP,
98 const HeuristicResolver *Resolver);
99std::optional<HighlightingKind> kindForDecl(
const NamedDecl *D,
100 const HeuristicResolver *Resolver) {
101 if (
auto *USD = dyn_cast<UsingShadowDecl>(D)) {
102 if (
auto *Target = USD->getTargetDecl())
105 if (
auto *TD = dyn_cast<TemplateDecl>(D)) {
106 if (
auto *Templated = TD->getTemplatedDecl())
109 if (
auto *TD = dyn_cast<TypedefNameDecl>(D)) {
112 kindForType(TD->getUnderlyingType().getTypePtrOrNull(), Resolver))
120 if (
auto *RD = llvm::dyn_cast<RecordDecl>(D)) {
126 if (isa<ClassTemplateDecl, RecordDecl, CXXConstructorDecl, ObjCInterfaceDecl,
127 ObjCImplementationDecl>(D))
129 if (isa<ObjCProtocolDecl>(D))
131 if (isa<ObjCCategoryDecl, ObjCCategoryImplDecl>(D))
133 if (
auto *MD = dyn_cast<CXXMethodDecl>(D))
136 if (
auto *OMD = dyn_cast<ObjCMethodDecl>(D))
139 if (isa<FieldDecl, IndirectFieldDecl, ObjCPropertyDecl>(D))
141 if (isa<EnumDecl>(D))
143 if (isa<EnumConstantDecl>(D))
145 if (isa<ParmVarDecl>(D))
147 if (
auto *VD = dyn_cast<VarDecl>(D)) {
148 if (isa<ImplicitParamDecl>(VD))
150 return VD->isStaticDataMember()
155 if (
const auto *BD = dyn_cast<BindingDecl>(D))
156 return BD->getDeclContext()->isFunctionOrMethod()
159 if (isa<FunctionDecl>(D))
161 if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D) ||
162 isa<UsingDirectiveDecl>(D))
164 if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
165 isa<NonTypeTemplateParmDecl>(D))
167 if (isa<ConceptDecl>(D))
169 if (isa<LabelDecl>(D))
171 if (
const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(D)) {
172 auto Targets = Resolver->resolveUsingValueDecl(UUVD);
173 if (!Targets.empty() && Targets[0] != UUVD) {
174 return kindForDecl(Targets[0], Resolver);
180std::optional<HighlightingKind> kindForType(
const Type *TP,
181 const HeuristicResolver *Resolver) {
184 if (TP->isBuiltinType())
186 if (
auto *TD = dyn_cast<TemplateTypeParmType>(TP))
187 return kindForDecl(TD->getDecl(), Resolver);
188 if (isa<ObjCObjectPointerType>(TP))
190 if (
auto *TD = TP->getAsTagDecl())
191 return kindForDecl(TD, Resolver);
196bool isConst(QualType T) {
199 T =
T.getNonReferenceType();
200 if (
T.isConstQualified())
202 if (
const auto *AT =
T->getAsArrayTypeUnsafe())
203 return isConst(AT->getElementType());
204 if (isConst(
T->getPointeeType()))
212bool isConst(
const Decl *D) {
213 if (llvm::isa<EnumConstantDecl>(D) || llvm::isa<NonTypeTemplateParmDecl>(D))
215 if (llvm::isa<FieldDecl>(D) || llvm::isa<VarDecl>(D) ||
216 llvm::isa<MSPropertyDecl>(D) || llvm::isa<BindingDecl>(D)) {
217 if (isConst(llvm::cast<ValueDecl>(D)->getType()))
220 if (
const auto *OCPD = llvm::dyn_cast<ObjCPropertyDecl>(D)) {
221 if (OCPD->isReadOnly())
224 if (
const auto *MPD = llvm::dyn_cast<MSPropertyDecl>(D)) {
225 if (!MPD->hasSetter())
228 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
254bool isStatic(
const Decl *D) {
255 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
256 return CMD->isStatic();
257 if (
const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
258 return VD->isStaticDataMember() || VD->isStaticLocal();
259 if (
const auto *OPD = llvm::dyn_cast<ObjCPropertyDecl>(D))
260 return OPD->isClassProperty();
261 if (
const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D))
262 return OMD->isClassMethod();
266bool isAbstract(
const Decl *D) {
267 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
268 return CMD->isPureVirtual();
269 if (
const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(D))
270 return CRD->hasDefinition() && CRD->isAbstract();
274bool isVirtual(
const Decl *D) {
275 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
276 return CMD->isVirtual();
280bool isDependent(
const Decl *D) {
281 if (isa<UnresolvedUsingValueDecl>(D))
289bool isDefaultLibrary(
const Decl *D) {
290 SourceLocation Loc =
D->getLocation();
293 return D->getASTContext().getSourceManager().isInSystemHeader(Loc);
296bool isDefaultLibrary(
const Type *T) {
302 if (
auto *TD = dyn_cast<TemplateTypeParmType>(
Underlying))
303 return isDefaultLibrary(TD->getDecl());
305 return isDefaultLibrary(TD);
312SourceLocation getHighlightableSpellingToken(SourceLocation L,
313 const SourceManager &SM) {
315 return SM.isWrittenInMainFile(L) ? L : SourceLocation{};
317 if (!SM.isMacroArgExpansion(L))
320 return getHighlightableSpellingToken(SM.getImmediateSpellingLoc(L), SM);
324 enum HighlightPriority { Dependent = 0, Resolved = 1 };
350 unsigned Priority1 = evaluateHighlightPriority(A);
351 unsigned Priority2 = evaluateHighlightPriority(B);
352 if (Priority1 == Priority2 &&
A.Kind !=
B.Kind)
354 auto Result = Priority1 > Priority2 ?
A :
B;
355 Result.Modifiers =
A.Modifiers |
B.Modifiers;
358std::optional<HighlightingToken>
359resolveConflict(ArrayRef<HighlightingToken> Tokens) {
360 if (Tokens.size() == 1)
363 assert(Tokens.size() >= 2);
364 std::optional<HighlightingToken> Winner =
365 resolveConflict(Tokens[0], Tokens[1]);
366 for (
size_t I = 2; Winner && I < Tokens.size(); ++I)
367 Winner = resolveConflict(*Winner, Tokens[I]);
373class HighlightingFilter {
375 HighlightingFilter() {
376 for (
auto &Active : ActiveKindLookup)
379 ActiveModifiersMask = ~0;
383 ActiveKindLookup[
static_cast<size_t>(Kind)] =
false;
387 ActiveModifiersMask &= ~(1 <<
static_cast<uint32_t
>(
Modifier));
391 return ActiveKindLookup[
static_cast<size_t>(Kind)];
394 uint32_t maskModifiers(uint32_t Modifiers)
const {
395 return Modifiers & ActiveModifiersMask;
398 static HighlightingFilter fromCurrentConfig() {
400 HighlightingFilter Filter;
401 for (
const auto &Kind :
C.SemanticTokens.DisabledKinds)
403 Filter.disableKind(*K);
404 for (
const auto &
Modifier :
C.SemanticTokens.DisabledModifiers)
406 Filter.disableModifier(*M);
413 uint32_t ActiveModifiersMask;
417class HighlightingsBuilder {
419 HighlightingsBuilder(
const ParsedAST &
AST,
const HighlightingFilter &Filter)
420 : TB(
AST.getTokens()), SourceMgr(
AST.getSourceManager()),
421 LangOpts(
AST.getLangOpts()), Filter(Filter),
422 Resolver(
AST.getHeuristicResolver()) {}
425 auto Range = getRangeForSourceLocation(Loc);
427 return InvalidHighlightingToken;
429 return addToken(*Range, Kind);
434 void addAngleBracketTokens(SourceLocation LLoc, SourceLocation RLoc) {
435 if (!LLoc.isValid() || !RLoc.isValid())
438 auto LRange = getRangeForSourceLocation(LLoc);
444 RLoc = SourceMgr.getFileLoc(RLoc);
446 RLoc = getHighlightableSpellingToken(RLoc, SourceMgr);
450 const auto *RTok = TB.spelledTokenContaining(RLoc);
454 if (!RTok || RTok->kind() == tok::greatergreater) {
463 if (RTok->kind() == tok::greater) {
464 if (
auto RRange = getRangeForSourceLocation(RLoc)) {
473 if (!Filter.isHighlightKindActive(Kind))
474 return InvalidHighlightingToken;
476 HighlightingToken HT;
479 Tokens.push_back(std::move(HT));
480 return Tokens.back();
484 if (
auto Range = getRangeForSourceLocation(Loc))
485 ExtraModifiers[*Range].push_back(
Modifier);
488 std::vector<HighlightingToken> collect(ParsedAST &
AST) && {
492 auto Last = llvm::unique(Tokens);
493 Tokens.erase(Last, Tokens.end());
498 std::vector<HighlightingToken> NonConflicting;
499 NonConflicting.reserve(Tokens.size());
500 for (ArrayRef<HighlightingToken> TokRef = Tokens; !TokRef.empty();) {
501 ArrayRef<HighlightingToken> Conflicting =
502 TokRef.take_while([&](
const HighlightingToken &T) {
505 return T.R == TokRef.front().R;
507 if (
auto Resolved = resolveConflict(Conflicting)) {
509 auto Modifiers = ExtraModifiers.find(Resolved->R);
510 if (Modifiers != ExtraModifiers.end()) {
512 Resolved->addModifier(Mod);
516 Resolved->Modifiers = Filter.maskModifiers(Resolved->Modifiers);
517 NonConflicting.push_back(*Resolved);
521 TokRef = TokRef.drop_front(Conflicting.size());
525 return NonConflicting;
527 const auto &SM =
AST.getSourceManager();
528 StringRef MainCode = SM.getBufferOrFake(SM.getMainFileID()).getBuffer();
531 std::vector<HighlightingToken> WithInactiveLines;
533 llvm::sort(SortedInactiveRegions);
534 auto It = NonConflicting.begin();
535 for (
const Range &R : SortedInactiveRegions) {
538 assert(R.start.line <= R.end.line);
539 for (
int Line = R.start.line; Line <= R.end.line; ++Line) {
541 for (; It != NonConflicting.end() && It->R.start.line < Line; ++It)
542 WithInactiveLines.push_back(std::move(*It));
544 auto EndOfLine = endOfLine(MainCode, Line);
546 HighlightingToken HT;
547 WithInactiveLines.emplace_back();
549 WithInactiveLines.back().R.start.line = Line;
550 WithInactiveLines.back().R.end = *EndOfLine;
552 elog(
"Failed to determine end of line: {0}", EndOfLine.takeError());
560 while (It != NonConflicting.end() && It->R.start.line == Line)
565 for (; It != NonConflicting.end(); ++It)
566 WithInactiveLines.push_back(std::move(*It));
567 return WithInactiveLines;
570 const HeuristicResolver *getResolver()
const {
return Resolver; }
573 std::optional<Range> getRangeForSourceLocation(SourceLocation Loc) {
574 Loc = getHighlightableSpellingToken(Loc, SourceMgr);
579 const auto *Tok = TB.spelledTokenContaining(Loc);
583 Tok->range(SourceMgr).toCharRange(SourceMgr));
586 const syntax::TokenBuffer &TB;
587 const SourceManager &SourceMgr;
588 const LangOptions &LangOpts;
589 HighlightingFilter Filter;
590 std::vector<HighlightingToken> Tokens;
591 std::map<Range, llvm::SmallVector<HighlightingModifier, 1>> ExtraModifiers;
592 const HeuristicResolver *Resolver;
594 HighlightingToken InvalidHighlightingToken;
597std::optional<HighlightingModifier> scopeModifier(
const NamedDecl *D) {
598 const DeclContext *DC =
D->getDeclContext();
600 if (
auto *R = dyn_cast_or_null<CXXRecordDecl>(D))
601 if (R->isInjectedClassName())
602 DC = DC->getParent();
604 if (llvm::isa<FieldDecl>(D))
605 if (
const auto *RD = llvm::dyn_cast<RecordDecl>(DC))
609 for (; !DC->isFileContext(); DC = DC->getParent()) {
610 if (DC->isFunctionOrMethod())
617 if (DC->isTranslationUnit() &&
D->isTemplateParameter())
620 if (llvm::to_underlying(
D->getLinkageInternal()) <
621 llvm::to_underlying(Linkage::External))
626std::optional<HighlightingModifier> scopeModifier(
const Type *T) {
629 if (
T->isBuiltinType())
631 if (
auto *TD = dyn_cast<TemplateTypeParmType>(T))
632 return scopeModifier(TD->getDecl());
633 if (
auto *TD =
T->getAsTagDecl())
634 return scopeModifier(TD);
640class CollectExtraHighlightings
641 :
public RecursiveASTVisitor<CollectExtraHighlightings> {
642 using Base = RecursiveASTVisitor<CollectExtraHighlightings>;
645 CollectExtraHighlightings(HighlightingsBuilder &H) : H(H) {}
647 bool VisitCXXConstructExpr(CXXConstructExpr *E) {
648 highlightMutableReferenceArguments(E->getConstructor(),
649 {E->getArgs(), E->getNumArgs()});
654 bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
655 if (Init->isMemberInitializer())
656 if (
auto *Member = Init->getMember())
657 highlightMutableReferenceArgument(Member->getType(), Init->getInit());
658 return Base::TraverseConstructorInitializer(Init);
661 bool TraverseTypeConstraint(
const TypeConstraint *C) {
662 if (
auto *Args =
C->getTemplateArgsAsWritten())
663 H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
664 return Base::TraverseTypeConstraint(C);
667 bool VisitPredefinedExpr(PredefinedExpr *E) {
675 bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
676 if (
auto *Args = E->getTemplateArgsAsWritten())
677 H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
681 bool VisitTemplateDecl(TemplateDecl *D) {
682 if (
auto *TPL =
D->getTemplateParameters())
683 H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
687 bool VisitTagDecl(TagDecl *D) {
688 for (
unsigned i = 0; i <
D->getNumTemplateParameterLists(); ++i) {
689 if (
auto *TPL =
D->getTemplateParameterList(i))
690 H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
696 VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D) {
697 if (
auto *Args =
D->getTemplateArgsAsWritten())
698 H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
702 bool VisitClassTemplatePartialSpecializationDecl(
703 ClassTemplatePartialSpecializationDecl *D) {
704 if (
auto *TPL =
D->getTemplateParameters())
705 H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
709 bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) {
710 if (
auto *Args =
D->getTemplateArgsAsWritten())
711 H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
715 bool VisitVarTemplatePartialSpecializationDecl(
716 VarTemplatePartialSpecializationDecl *D) {
717 if (
auto *TPL =
D->getTemplateParameters())
718 H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
722 bool VisitDeclRefExpr(DeclRefExpr *E) {
723 H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc());
726 bool VisitMemberExpr(MemberExpr *E) {
727 H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc());
731 bool VisitFunctionDecl(FunctionDecl *D) {
732 if (
D->isOverloadedOperator()) {
733 const auto AddOpDeclToken = [&](SourceLocation Loc) {
736 if (
D->isThisDeclarationADefinition())
739 const auto Range =
D->getNameInfo().getCXXOperatorNameRange();
740 AddOpDeclToken(Range.getBegin());
741 const auto Kind =
D->getOverloadedOperator();
742 if (Kind == OO_Call || Kind == OO_Subscript)
743 AddOpDeclToken(Range.getEnd());
745 if (
auto *Args =
D->getTemplateSpecializationArgsAsWritten())
746 H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
750 bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
751 const auto AddOpToken = [&](SourceLocation Loc) {
755 AddOpToken(E->getOperatorLoc());
756 const auto Kind = E->getOperator();
757 if (Kind == OO_Call || Kind == OO_Subscript) {
758 if (
auto *Callee = E->getCallee())
759 AddOpToken(Callee->getBeginLoc());
764 bool VisitUnaryOperator(UnaryOperator *Op) {
766 if (Op->getSubExpr()->isTypeDependent())
771 bool VisitBinaryOperator(BinaryOperator *Op) {
773 if (Op->getLHS()->isTypeDependent() || Op->getRHS()->isTypeDependent())
778 bool VisitConditionalOperator(ConditionalOperator *Op) {
784 bool VisitCXXNewExpr(CXXNewExpr *E) {
786 if (isa_and_present<CXXMethodDecl>(E->getOperatorNew()))
791 bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
793 if (isa_and_present<CXXMethodDecl>(E->getOperatorDelete()))
798 bool VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
799 const auto &
B = E->getAngleBrackets();
800 H.addAngleBracketTokens(
B.getBegin(),
B.getEnd());
804 bool VisitCallExpr(CallExpr *E) {
807 if (isa<UserDefinedLiteral>(E))
812 llvm::ArrayRef<const Expr *> Args = {E->getArgs(), E->getNumArgs()};
813 if (
auto *CallOp = dyn_cast<CXXOperatorCallExpr>(E)) {
814 switch (CallOp->getOperator()) {
817 Args = Args.drop_front();
824 highlightMutableReferenceArguments(
825 dyn_cast_or_null<FunctionDecl>(E->getCalleeDecl()), Args);
830 void highlightMutableReferenceArgument(QualType T,
const Expr *Arg) {
837 bool IsRef =
T->isLValueReferenceType();
838 bool IsPtr =
T->isPointerType();
839 if ((!IsRef && !IsPtr) ||
T->getPointeeType().isConstQualified() ||
840 T->isDependentType()) {
844 std::optional<SourceLocation> Location;
849 if (
auto *IC = dyn_cast<ImplicitCastExpr>(Arg))
850 Arg = IC->getSubExprAsWritten();
851 if (
auto *UO = dyn_cast<UnaryOperator>(Arg)) {
852 if (UO->getOpcode() == UO_AddrOf)
853 Arg = UO->getSubExpr();
855 if (
auto *DR = dyn_cast<DeclRefExpr>(Arg))
856 Location = DR->getLocation();
857 else if (
auto *M = dyn_cast<MemberExpr>(Arg))
858 Location = M->getMemberLoc();
861 H.addExtraModifier(*Location,
867 highlightMutableReferenceArguments(
const FunctionDecl *FD,
868 llvm::ArrayRef<const Expr *const> Args) {
872 if (
auto *ProtoType = FD->getType()->getAs<FunctionProtoType>()) {
877 I < std::min(
size_t(ProtoType->getNumParams()), Args.size()); ++I) {
878 highlightMutableReferenceArgument(ProtoType->getParamType(I), Args[I]);
883 bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) {
884 if (
auto K = kindForType(L.getTypePtr(), H.getResolver())) {
885 auto &Tok = H.addToken(L.getBeginLoc(), *K)
887 if (
auto Mod = scopeModifier(L.getTypePtr()))
888 Tok.addModifier(*Mod);
889 if (isDefaultLibrary(L.getTypePtr()))
895 bool VisitCXXDestructorDecl(CXXDestructorDecl *D) {
896 if (
auto *TI =
D->getNameInfo().getNamedTypeInfo()) {
897 SourceLocation Loc = TI->getTypeLoc().getBeginLoc();
900 if (
D->isThisDeclarationADefinition())
906 bool VisitCXXMemberCallExpr(CXXMemberCallExpr *CE) {
909 if (
auto *D = CE->getMethodDecl()) {
910 if (isa<CXXDestructorDecl>(D)) {
911 if (
auto *ME = dyn_cast<MemberExpr>(CE->getCallee())) {
912 if (
auto *TI = ME->getMemberNameInfo().getNamedTypeInfo()) {
913 H.addExtraModifier(TI->getTypeLoc().getBeginLoc(),
917 }
else if (
D->isOverloadedOperator()) {
918 if (
auto *ME = dyn_cast<MemberExpr>(CE->getCallee()))
920 ME->getMemberNameInfo().getCXXOperatorNameRange().getBegin(),
928 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
929 for (
unsigned i = 0; i <
D->getNumTemplateParameterLists(); ++i) {
930 if (
auto *TPL =
D->getTemplateParameterList(i))
931 H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());
933 auto *AT =
D->getType()->getContainedAutoType();
937 kindForType(AT->getDeducedType().getTypePtrOrNull(), H.getResolver());
940 auto *TSI =
D->getTypeSourceInfo();
943 SourceLocation StartLoc =
944 TSI->getTypeLoc().getContainedAutoTypeLoc().getNameLoc();
949 if (StartLoc ==
D->getLocation())
954 const Type *
Deduced = AT->getDeducedType().getTypePtrOrNull();
955 if (
auto Mod = scopeModifier(
Deduced))
956 Tok.addModifier(*Mod);
964 void highlightObjCSelector(
const ArrayRef<SourceLocation> &Locs,
bool Decl,
968 for (SourceLocation Part : Locs) {
982 bool VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
983 llvm::SmallVector<SourceLocation> Locs;
984 OMD->getSelectorLocs(Locs);
985 highlightObjCSelector(Locs,
true,
986 OMD->isThisDeclarationADefinition(),
987 OMD->isClassMethod(), isDefaultLibrary(OMD));
991 bool VisitObjCMessageExpr(ObjCMessageExpr *OME) {
992 llvm::SmallVector<SourceLocation> Locs;
993 OME->getSelectorLocs(Locs);
995 if (ObjCMethodDecl *OMD = OME->getMethodDecl())
997 highlightObjCSelector(Locs,
false,
false,
1006 void highlightObjCImplicitPropertyRef(
const ObjCMethodDecl *OMD,
1007 SourceLocation Loc) {
1010 if (OMD->isClassMethod())
1012 if (isDefaultLibrary(OMD))
1016 bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *OPRE) {
1020 if (!OPRE->isImplicitProperty())
1026 if (OPRE->isMessagingGetter()) {
1027 highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertyGetter(),
1028 OPRE->getLocation());
1031 if (OPRE->isMessagingSetter()) {
1032 highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertySetter(),
1033 OPRE->getLocation());
1038 bool VisitOverloadExpr(OverloadExpr *E) {
1039 H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc());
1040 if (!E->decls().empty())
1044 if (llvm::isa<UnresolvedMemberExpr>(E))
1050 bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
1054 H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc());
1058 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
1062 H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc());
1066 bool VisitAttr(Attr *A) {
1067 switch (
A->getKind()) {
1068 case attr::Override:
1078 bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
1085 bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) {
1086 if (!L.getTypePtr()->getTemplateName().getAsTemplateDecl(
1091 H.addAngleBracketTokens(L.getLAngleLoc(), L.getRAngleLoc());
1095 bool TraverseTemplateArgumentLoc(TemplateArgumentLoc L) {
1098 if (L.getArgument().getKind() != TemplateArgument::Template &&
1099 L.getArgument().getKind() != TemplateArgument::TemplateExpansion)
1100 return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
1102 TemplateName N = L.getArgument().getAsTemplateOrTemplatePattern();
1103 switch (N.getKind()) {
1104 case TemplateName::OverloadedTemplate:
1109 case TemplateName::DependentTemplate:
1110 case TemplateName::AssumedTemplate:
1114 case TemplateName::Template:
1115 case TemplateName::QualifiedTemplate:
1116 case TemplateName::SubstTemplateTemplateParm:
1117 case TemplateName::SubstTemplateTemplateParmPack:
1118 case TemplateName::UsingTemplate:
1119 case TemplateName::DeducedTemplate:
1123 return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
1127 HighlightingsBuilder &H;
1131std::vector<HighlightingToken>
1133 auto &C =
AST.getASTContext();
1134 HighlightingFilter Filter = HighlightingFilter::fromCurrentConfig();
1135 if (!IncludeInactiveRegionTokens)
1138 HighlightingsBuilder Builder(
AST, Filter);
1140 CollectExtraHighlightings(Builder).TraverseAST(C);
1145 for (
const NamedDecl *Decl : R.
Targets) {
1146 if (!canHighlightName(Decl->getDeclName()))
1148 auto Kind = kindForDecl(Decl,
AST.getHeuristicResolver());
1151 auto &Tok = Builder.addToken(R.
NameLoc, *Kind);
1154 if (
auto *TD = dyn_cast<TemplateDecl>(Decl)) {
1155 if (
auto *Templated = TD->getTemplatedDecl())
1158 if (
auto Mod = scopeModifier(Decl))
1159 Tok.addModifier(*Mod);
1164 if (isAbstract(Decl))
1166 if (isVirtual(Decl))
1168 if (isDependent(Decl))
1170 if (isDefaultLibrary(Decl))
1172 if (Decl->isDeprecated())
1174 if (isa<CXXConstructorDecl>(Decl))
1180 if (!isa<UnresolvedUsingValueDecl>(Decl))
1182 if (isUniqueDefinition(Decl))
1187 AST.getHeuristicResolver());
1190 auto &T = Builder.addToken(M.toRange(C.getSourceManager()),
1196 for (
const auto &SIDToRefs :
AST.getMacros().MacroRefs)
1197 for (
const auto &M : SIDToRefs.second)
1199 for (
const auto &M :
AST.getMacros().UnknownMacros)
1202 return std::move(Builder).collect(
AST);
1208 return OS <<
"Variable";
1210 return OS <<
"LocalVariable";
1212 return OS <<
"Parameter";
1214 return OS <<
"Function";
1216 return OS <<
"Method";
1218 return OS <<
"StaticMethod";
1220 return OS <<
"Field";
1222 return OS <<
"StaticField";
1224 return OS <<
"Class";
1226 return OS <<
"Interface";
1228 return OS <<
"Enum";
1230 return OS <<
"EnumConstant";
1232 return OS <<
"Typedef";
1234 return OS <<
"Type";
1236 return OS <<
"Unknown";
1238 return OS <<
"Namespace";
1240 return OS <<
"TemplateParameter";
1242 return OS <<
"Concept";
1244 return OS <<
"Primitive";
1246 return OS <<
"Macro";
1248 return OS <<
"Modifier";
1250 return OS <<
"Operator";
1252 return OS <<
"Bracket";
1254 return OS <<
"Label";
1256 return OS <<
"InactiveCode";
1258 llvm_unreachable(
"invalid HighlightingKind");
1260std::optional<HighlightingKind>
1262 static llvm::StringMap<HighlightingKind> Lookup = {
1289 auto It = Lookup.find(Name);
1290 return It != Lookup.end() ? std::make_optional(It->getValue()) : std::nullopt;
1295 return OS <<
"decl";
1299 return OS <<
"constrDestr";
1304std::optional<HighlightingModifier>
1306 static llvm::StringMap<HighlightingModifier> Lookup = {
1319 {
"ConstructorOrDestructor",
1328 auto It = Lookup.find(Name);
1329 return It != Lookup.end() ? std::make_optional(It->getValue()) : std::nullopt;
1341std::vector<SemanticToken>
1343 llvm::StringRef Code) {
1344 assert(llvm::is_sorted(Tokens));
1345 std::vector<SemanticToken> Result;
1352 Result.emplace_back();
1356 assert(Tok.R.start.line >= Last->
R.
end.
line);
1368 Out->
tokenType =
static_cast<unsigned>(Tok.Kind);
1372 if (Tok.R.end.line == Tok.R.start.line) {
1373 Out->
length = Tok.R.end.character - Tok.R.start.character;
1383 for (
int I = Tok.R.start.line; I < Tok.R.end.line; ++I) {
1384 auto LineEnd = Code.find(
'\n', TokStartOffset);
1385 assert(LineEnd != Code.npos);
1386 Out->
length = LineEnd - TokStartOffset;
1388 TokStartOffset = LineEnd + 1;
1389 Result.emplace_back();
1390 Out = &Result.back();
1391 *Out = Result[Result.size() - 2];
1397 Out->
length = Tok.R.end.character;
1432 return "enumMember";
1441 return "typeParameter";
1459 llvm_unreachable(
"unhandled HighlightingKind");
1465 return "declaration";
1467 return "definition";
1469 return "deprecated";
1481 return "dependentName";
1483 return "defaultLibrary";
1485 return "usedAsMutableReference";
1487 return "usedAsMutablePointer";
1489 return "constructorOrDestructor";
1491 return "userDefined";
1493 return "functionScope";
1495 return "classScope";
1499 return "globalScope";
1501 llvm_unreachable(
"unhandled HighlightingModifier");
1504std::vector<SemanticTokensEdit>
1506 llvm::ArrayRef<SemanticToken> New) {
1510 unsigned Offset = 0;
1511 while (!Old.empty() && !New.empty() && Old.front() == New.front()) {
1513 Old = Old.drop_front();
1514 New = New.drop_front();
1516 while (!Old.empty() && !New.empty() && Old.back() == New.back()) {
1517 Old = Old.drop_back();
1518 New = New.drop_back();
1521 if (Old.empty() && New.empty())
1524 Edit.startToken = Offset;
1525 Edit.deleteTokens = Old.size();
1527 return {std::move(
Edit)};
1531 std::vector<Range> SkippedRanges(std::move(
AST.getMacros().SkippedRanges));
1532 const auto &SM =
AST.getSourceManager();
1533 StringRef MainCode = SM.getBufferOrFake(SM.getMainFileID()).getBuffer();
1534 std::vector<Range> InactiveRegions;
1535 for (
const Range &Skipped : SkippedRanges) {
1536 Range Inactive = Skipped;
1554 if (
auto EndOfLine = endOfLine(MainCode, Inactive.
end.
line)) {
1555 Inactive.
end = *EndOfLine;
1557 elog(
"Failed to determine end of line: {0}", EndOfLine.takeError());
1560 InactiveRegions.push_back(Inactive);
1562 return InactiveRegions;
static cl::opt< std::string > Config("config", desc(R"(
Specifies a configuration in YAML/JSON format:
-config="{Checks:' *', CheckOptions:{x:y}}"
When the value is empty, clang-tidy will
attempt to find a file named .clang-tidy for
each source file in its parent directories.
)"), cl::init(""), cl::cat(ClangTidyCategory))
Stores and provides access to parsed AST.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
std::optional< HighlightingModifier > highlightingModifierFromString(llvm::StringRef Name)
llvm::StringRef toSemanticTokenModifier(HighlightingModifier Modifier)
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST, bool IncludeInactiveRegionTokens)
std::optional< HighlightingKind > highlightingKindFromString(llvm::StringRef Name)
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
llvm::StringRef toSemanticTokenType(HighlightingKind Kind)
size_t lspLength(llvm::StringRef Code)
std::vector< SemanticToken > toSemanticTokens(llvm::ArrayRef< HighlightingToken > Tokens, llvm::StringRef Code)
std::vector< SemanticTokensEdit > diffTokens(llvm::ArrayRef< SemanticToken > Old, llvm::ArrayRef< SemanticToken > New)
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.
bool operator==(const Inclusion &LHS, const Inclusion &RHS)
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
bool operator<(const Ref &L, const Ref &R)
@ Type
An inlay hint that for a type annotation.
std::vector< Range > getInactiveRegions(ParsedAST &AST)
void elog(const char *Fmt, Ts &&... Vals)
@ Underlying
This is the underlying declaration for a renaming-alias, decltype etc.
@ ConstructorOrDestructor
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static const Config & current()
Returns the Config of the current Context, or an empty configuration.
A set of edits generated for a single file.
int line
Line position in a document (zero-based).
int character
Character offset on a line in a document (zero-based).
Position start
The range's start position.
Position end
The range's end position.
Information about a reference written in the source code, independent of the actual AST node that thi...
bool IsDecl
True if the reference is a declaration or definition;.
SourceLocation NameLoc
Start location of the last name part, i.e. 'foo' in 'ns::foo<int>'.
llvm::SmallVector< const NamedDecl *, 1 > Targets
A list of targets referenced by this name.
Specifies a single semantic token in the document.
unsigned length
the length of the token. A token cannot be multiline
unsigned deltaStart
token start character, relative to the previous token (relative to 0 or the previous token's start if...
unsigned deltaLine
token line number, relative to the previous token
unsigned tokenType
will be looked up in SemanticTokensLegend.tokenTypes
unsigned tokenModifiers
each set bit will be looked up in SemanticTokensLegend.tokenModifiers
Describes a replacement of a contiguous range of semanticTokens.