2019-06-27 20:22:18 +08:00
|
|
|
//===--- SemanticHighlighting.cpp - ------------------------- ---*- C++ -*-===//
|
2019-06-26 21:08:36 +08:00
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "SemanticHighlighting.h"
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
#include "FindTarget.h"
|
2021-05-03 13:18:49 +08:00
|
|
|
#include "HeuristicResolver.h"
|
2019-09-04 17:46:06 +08:00
|
|
|
#include "ParsedAST.h"
|
2019-07-04 15:53:12 +08:00
|
|
|
#include "Protocol.h"
|
2019-06-26 21:08:36 +08:00
|
|
|
#include "SourceCode.h"
|
[clangd] Move non-clang base pieces into separate support/ lib. NFCI
Summary:
This enforces layering, reduces a sprawling clangd/ directory, and makes life
easier for embedders.
Reviewers: kbobyrev
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D79014
2020-04-28 23:49:17 +08:00
|
|
|
#include "support/Logger.h"
|
2019-06-26 21:08:36 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2019-08-19 15:51:39 +08:00
|
|
|
#include "clang/AST/Decl.h"
|
2019-08-09 20:19:10 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2021-01-27 16:47:17 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2019-09-17 00:16:03 +08:00
|
|
|
#include "clang/AST/DeclarationName.h"
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2019-06-26 21:08:36 +08:00
|
|
|
#include "clang/AST/RecursiveASTVisitor.h"
|
[clangd] Highlight typedefs to template parameters as template parameters
Summary:
Template parameters were handled outside `addType`, this led to lack of highlightings for typedefs
to template types.
This was never desirable, we want to highlight our typedefs as their underlying type.
Note that typedefs to more complicated types, like pointers and references are still not highlighted.
Original patch by Johan Vikström.
Reviewers: hokein, jvikstrom
Reviewed By: hokein
Subscribers: nridge, javed.absar, kristof.beyls, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66516
llvm-svn: 371379
2019-09-09 17:37:17 +08:00
|
|
|
#include "clang/AST/Type.h"
|
|
|
|
#include "clang/AST/TypeLoc.h"
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
#include "clang/Basic/LangOptions.h"
|
2019-09-09 22:33:10 +08:00
|
|
|
#include "clang/Basic/SourceLocation.h"
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2020-03-01 23:04:07 +08:00
|
|
|
#include "clang/Tooling/Syntax/Tokens.h"
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
#include "llvm/ADT/None.h"
|
|
|
|
#include "llvm/ADT/Optional.h"
|
2019-09-25 06:17:55 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2020-03-03 18:10:38 +08:00
|
|
|
#include "llvm/Support/Base64.h"
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
2019-08-01 16:08:44 +08:00
|
|
|
#include <algorithm>
|
2019-06-26 21:08:36 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace {
|
|
|
|
|
2019-09-17 00:16:03 +08:00
|
|
|
/// Some names are not written in the source code and cannot be highlighted,
|
|
|
|
/// e.g. anonymous classes. This function detects those cases.
|
|
|
|
bool canHighlightName(DeclarationName Name) {
|
2021-02-28 05:08:07 +08:00
|
|
|
switch (Name.getNameKind()) {
|
|
|
|
case DeclarationName::Identifier: {
|
|
|
|
auto *II = Name.getAsIdentifierInfo();
|
|
|
|
return II && !II->getName().empty();
|
|
|
|
}
|
|
|
|
case DeclarationName::CXXConstructorName:
|
|
|
|
case DeclarationName::CXXDestructorName:
|
2019-09-17 00:16:03 +08:00
|
|
|
return true;
|
2021-02-28 05:08:07 +08:00
|
|
|
case DeclarationName::ObjCZeroArgSelector:
|
|
|
|
case DeclarationName::ObjCOneArgSelector:
|
|
|
|
case DeclarationName::ObjCMultiArgSelector:
|
|
|
|
// Multi-arg selectors need special handling, and we handle 0/1 arg
|
|
|
|
// selectors there too.
|
|
|
|
return false;
|
|
|
|
case DeclarationName::CXXConversionFunctionName:
|
|
|
|
case DeclarationName::CXXOperatorName:
|
|
|
|
case DeclarationName::CXXDeductionGuideName:
|
|
|
|
case DeclarationName::CXXLiteralOperatorName:
|
|
|
|
case DeclarationName::CXXUsingDirective:
|
|
|
|
return false;
|
|
|
|
}
|
2021-03-05 11:24:55 +08:00
|
|
|
llvm_unreachable("invalid name kind");
|
2019-09-17 00:16:03 +08:00
|
|
|
}
|
|
|
|
|
2021-03-22 14:43:41 +08:00
|
|
|
llvm::Optional<HighlightingKind> kindForType(const Type *TP,
|
|
|
|
const HeuristicResolver *Resolver);
|
|
|
|
llvm::Optional<HighlightingKind>
|
|
|
|
kindForDecl(const NamedDecl *D, const HeuristicResolver *Resolver) {
|
2019-10-28 20:42:20 +08:00
|
|
|
if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
|
|
|
|
if (auto *Target = USD->getTargetDecl())
|
|
|
|
D = Target;
|
|
|
|
}
|
2019-10-15 02:26:13 +08:00
|
|
|
if (auto *TD = dyn_cast<TemplateDecl>(D)) {
|
|
|
|
if (auto *Templated = TD->getTemplatedDecl())
|
|
|
|
D = Templated;
|
|
|
|
}
|
2019-09-17 00:16:03 +08:00
|
|
|
if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
|
|
|
|
// We try to highlight typedefs as their underlying type.
|
2021-03-22 14:43:41 +08:00
|
|
|
if (auto K =
|
|
|
|
kindForType(TD->getUnderlyingType().getTypePtrOrNull(), Resolver))
|
2019-09-17 00:16:03 +08:00
|
|
|
return K;
|
|
|
|
// And fallback to a generic kind if this fails.
|
|
|
|
return HighlightingKind::Typedef;
|
|
|
|
}
|
|
|
|
// We highlight class decls, constructor decls and destructor decls as
|
2019-10-28 18:31:06 +08:00
|
|
|
// `Class` type. The destructor decls are handled in `VisitTagTypeLoc` (we
|
2019-09-17 00:16:03 +08:00
|
|
|
// will visit a TypeLoc where the underlying Type is a CXXRecordDecl).
|
|
|
|
if (auto *RD = llvm::dyn_cast<RecordDecl>(D)) {
|
|
|
|
// We don't want to highlight lambdas like classes.
|
|
|
|
if (RD->isLambda())
|
|
|
|
return llvm::None;
|
|
|
|
return HighlightingKind::Class;
|
|
|
|
}
|
2021-02-28 05:08:07 +08:00
|
|
|
if (isa<ClassTemplateDecl, RecordDecl, CXXConstructorDecl, ObjCInterfaceDecl,
|
|
|
|
ObjCImplementationDecl>(D))
|
2019-09-17 00:16:03 +08:00
|
|
|
return HighlightingKind::Class;
|
2021-02-28 05:08:07 +08:00
|
|
|
if (isa<ObjCProtocolDecl>(D))
|
|
|
|
return HighlightingKind::Interface;
|
|
|
|
if (isa<ObjCCategoryDecl>(D))
|
|
|
|
return HighlightingKind::Namespace;
|
2019-09-17 00:16:03 +08:00
|
|
|
if (auto *MD = dyn_cast<CXXMethodDecl>(D))
|
|
|
|
return MD->isStatic() ? HighlightingKind::StaticMethod
|
|
|
|
: HighlightingKind::Method;
|
2021-02-28 05:08:07 +08:00
|
|
|
if (auto *OMD = dyn_cast<ObjCMethodDecl>(D))
|
|
|
|
return OMD->isClassMethod() ? HighlightingKind::StaticMethod
|
|
|
|
: HighlightingKind::Method;
|
|
|
|
if (isa<FieldDecl, ObjCPropertyDecl>(D))
|
2019-09-17 00:16:03 +08:00
|
|
|
return HighlightingKind::Field;
|
|
|
|
if (isa<EnumDecl>(D))
|
|
|
|
return HighlightingKind::Enum;
|
|
|
|
if (isa<EnumConstantDecl>(D))
|
|
|
|
return HighlightingKind::EnumConstant;
|
|
|
|
if (isa<ParmVarDecl>(D))
|
|
|
|
return HighlightingKind::Parameter;
|
2021-02-28 05:08:07 +08:00
|
|
|
if (auto *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
if (isa<ImplicitParamDecl>(VD)) // e.g. ObjC Self
|
|
|
|
return llvm::None;
|
2019-09-17 00:16:03 +08:00
|
|
|
return VD->isStaticDataMember()
|
|
|
|
? HighlightingKind::StaticField
|
|
|
|
: VD->isLocalVarDecl() ? HighlightingKind::LocalVariable
|
|
|
|
: HighlightingKind::Variable;
|
2021-02-28 05:08:07 +08:00
|
|
|
}
|
2020-08-07 13:31:03 +08:00
|
|
|
if (const auto *BD = dyn_cast<BindingDecl>(D))
|
|
|
|
return BD->getDeclContext()->isFunctionOrMethod()
|
|
|
|
? HighlightingKind::LocalVariable
|
|
|
|
: HighlightingKind::Variable;
|
2019-09-17 00:16:03 +08:00
|
|
|
if (isa<FunctionDecl>(D))
|
|
|
|
return HighlightingKind::Function;
|
|
|
|
if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D) ||
|
|
|
|
isa<UsingDirectiveDecl>(D))
|
|
|
|
return HighlightingKind::Namespace;
|
|
|
|
if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
|
|
|
|
isa<NonTypeTemplateParmDecl>(D))
|
|
|
|
return HighlightingKind::TemplateParameter;
|
2020-01-22 02:21:08 +08:00
|
|
|
if (isa<ConceptDecl>(D))
|
|
|
|
return HighlightingKind::Concept;
|
2021-03-22 14:43:41 +08:00
|
|
|
if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(D)) {
|
|
|
|
auto Targets = Resolver->resolveUsingValueDecl(UUVD);
|
|
|
|
if (!Targets.empty()) {
|
|
|
|
return kindForDecl(Targets[0], Resolver);
|
|
|
|
}
|
2021-03-22 14:13:53 +08:00
|
|
|
return HighlightingKind::Unknown;
|
|
|
|
}
|
2019-09-17 00:16:03 +08:00
|
|
|
return llvm::None;
|
|
|
|
}
|
2021-03-22 14:43:41 +08:00
|
|
|
llvm::Optional<HighlightingKind>
|
|
|
|
kindForType(const Type *TP, const HeuristicResolver *Resolver) {
|
2019-09-17 00:16:03 +08:00
|
|
|
if (!TP)
|
|
|
|
return llvm::None;
|
|
|
|
if (TP->isBuiltinType()) // Builtins are special, they do not have decls.
|
|
|
|
return HighlightingKind::Primitive;
|
|
|
|
if (auto *TD = dyn_cast<TemplateTypeParmType>(TP))
|
2021-03-22 14:43:41 +08:00
|
|
|
return kindForDecl(TD->getDecl(), Resolver);
|
2021-02-28 05:08:07 +08:00
|
|
|
if (isa<ObjCObjectPointerType>(TP))
|
|
|
|
return HighlightingKind::Class;
|
2019-09-17 00:16:03 +08:00
|
|
|
if (auto *TD = TP->getAsTagDecl())
|
2021-03-22 14:43:41 +08:00
|
|
|
return kindForDecl(TD, Resolver);
|
2019-09-17 00:16:03 +08:00
|
|
|
return llvm::None;
|
|
|
|
}
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
|
2021-01-27 16:47:17 +08:00
|
|
|
// Whether T is const in a loose sense - is a variable with this type readonly?
|
|
|
|
bool isConst(QualType T) {
|
|
|
|
if (T.isNull() || T->isDependentType())
|
|
|
|
return false;
|
|
|
|
T = T.getNonReferenceType();
|
|
|
|
if (T.isConstQualified())
|
|
|
|
return true;
|
|
|
|
if (const auto *AT = T->getAsArrayTypeUnsafe())
|
|
|
|
return isConst(AT->getElementType());
|
|
|
|
if (isConst(T->getPointeeType()))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Whether D is const in a loose sense (should it be highlighted as such?)
|
|
|
|
// FIXME: This is separate from whether *a particular usage* can mutate D.
|
|
|
|
// We may want V in V.size() to be readonly even if V is mutable.
|
|
|
|
bool isConst(const Decl *D) {
|
|
|
|
if (llvm::isa<EnumConstantDecl>(D) || llvm::isa<NonTypeTemplateParmDecl>(D))
|
|
|
|
return true;
|
|
|
|
if (llvm::isa<FieldDecl>(D) || llvm::isa<VarDecl>(D) ||
|
|
|
|
llvm::isa<MSPropertyDecl>(D) || llvm::isa<BindingDecl>(D)) {
|
|
|
|
if (isConst(llvm::cast<ValueDecl>(D)->getType()))
|
|
|
|
return true;
|
2019-10-15 02:26:13 +08:00
|
|
|
}
|
2021-01-27 16:47:17 +08:00
|
|
|
if (const auto *OCPD = llvm::dyn_cast<ObjCPropertyDecl>(D)) {
|
|
|
|
if (OCPD->isReadOnly())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (const auto *MPD = llvm::dyn_cast<MSPropertyDecl>(D)) {
|
|
|
|
if (!MPD->hasSetter())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {
|
|
|
|
if (CMD->isConst())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// "Static" means many things in C++, only some get the "static" modifier.
|
|
|
|
//
|
|
|
|
// Meanings that do:
|
|
|
|
// - Members associated with the class rather than the instance.
|
|
|
|
// This is what 'static' most often means across languages.
|
|
|
|
// - static local variables
|
|
|
|
// These are similarly "detached from their context" by the static keyword.
|
|
|
|
// In practice, these are rarely used inside classes, reducing confusion.
|
|
|
|
//
|
|
|
|
// Meanings that don't:
|
|
|
|
// - Namespace-scoped variables, which have static storage class.
|
|
|
|
// This is implicit, so the keyword "static" isn't so strongly associated.
|
|
|
|
// If we want a modifier for these, "global scope" is probably the concept.
|
|
|
|
// - Namespace-scoped variables/functions explicitly marked "static".
|
|
|
|
// There the keyword changes *linkage* , which is a totally different concept.
|
|
|
|
// If we want to model this, "file scope" would be a nice modifier.
|
|
|
|
//
|
|
|
|
// This is confusing, and maybe we should use another name, but because "static"
|
|
|
|
// is a standard LSP modifier, having one with that name has advantages.
|
|
|
|
bool isStatic(const Decl *D) {
|
|
|
|
if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
|
|
|
|
return CMD->isStatic();
|
|
|
|
if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
|
|
|
|
return VD->isStaticDataMember() || VD->isStaticLocal();
|
|
|
|
if (const auto *OPD = llvm::dyn_cast<ObjCPropertyDecl>(D))
|
|
|
|
return OPD->isClassProperty();
|
|
|
|
if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D))
|
|
|
|
return OMD->isClassMethod();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isAbstract(const Decl *D) {
|
|
|
|
if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
|
|
|
|
return CMD->isPure();
|
|
|
|
if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(D))
|
|
|
|
return CRD->hasDefinition() && CRD->isAbstract();
|
|
|
|
return false;
|
2019-10-15 02:26:13 +08:00
|
|
|
}
|
2019-09-17 00:16:03 +08:00
|
|
|
|
2021-08-04 10:53:01 +08:00
|
|
|
bool isVirtual(const Decl *D) {
|
|
|
|
if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D))
|
|
|
|
return CMD->isVirtual();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-03-22 14:13:53 +08:00
|
|
|
bool isDependent(const Decl *D) {
|
|
|
|
if (isa<UnresolvedUsingValueDecl>(D))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-30 01:03:10 +08:00
|
|
|
/// Returns true if `Decl` is considered to be from a default/system library.
|
|
|
|
/// This currently checks the systemness of the file by include type, although
|
|
|
|
/// different heuristics may be used in the future (e.g. sysroot paths).
|
|
|
|
bool isDefaultLibrary(const Decl *D) {
|
|
|
|
SourceLocation Loc = D->getLocation();
|
|
|
|
if (!Loc.isValid())
|
|
|
|
return false;
|
|
|
|
return D->getASTContext().getSourceManager().isInSystemHeader(Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDefaultLibrary(const Type *T) {
|
|
|
|
if (!T)
|
|
|
|
return false;
|
|
|
|
const Type *Underlying = T->getPointeeOrArrayElementType();
|
|
|
|
if (Underlying->isBuiltinType())
|
|
|
|
return true;
|
|
|
|
if (auto *TD = dyn_cast<TemplateTypeParmType>(Underlying))
|
|
|
|
return isDefaultLibrary(TD->getDecl());
|
|
|
|
if (auto *TD = Underlying->getAsTagDecl())
|
|
|
|
return isDefaultLibrary(TD);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-01 23:04:07 +08:00
|
|
|
// For a macro usage `DUMP(foo)`, we want:
|
|
|
|
// - DUMP --> "macro"
|
|
|
|
// - foo --> "variable".
|
|
|
|
SourceLocation getHighlightableSpellingToken(SourceLocation L,
|
|
|
|
const SourceManager &SM) {
|
|
|
|
if (L.isFileID())
|
|
|
|
return SM.isWrittenInMainFile(L) ? L : SourceLocation{};
|
|
|
|
// Tokens expanded from the macro body contribute no highlightings.
|
|
|
|
if (!SM.isMacroArgExpansion(L))
|
|
|
|
return {};
|
|
|
|
// Tokens expanded from macro args are potentially highlightable.
|
|
|
|
return getHighlightableSpellingToken(SM.getImmediateSpellingLoc(L), SM);
|
|
|
|
}
|
|
|
|
|
2021-01-30 08:12:36 +08:00
|
|
|
unsigned evaluateHighlightPriority(const HighlightingToken &Tok) {
|
2020-03-20 03:42:10 +08:00
|
|
|
enum HighlightPriority { Dependent = 0, Resolved = 1 };
|
2021-01-30 08:12:36 +08:00
|
|
|
return (Tok.Modifiers & (1 << uint32_t(HighlightingModifier::DependentName)))
|
2020-03-20 03:42:10 +08:00
|
|
|
? Dependent
|
|
|
|
: Resolved;
|
|
|
|
}
|
|
|
|
|
2021-01-30 08:12:36 +08:00
|
|
|
// Sometimes we get multiple tokens at the same location:
|
|
|
|
//
|
|
|
|
// - findExplicitReferences() returns a heuristic result for a dependent name
|
|
|
|
// (e.g. Method) and CollectExtraHighlighting returning a fallback dependent
|
|
|
|
// highlighting (e.g. Unknown+Dependent).
|
|
|
|
// - macro arguments are expanded multiple times and have different roles
|
|
|
|
// - broken code recovery produces several AST nodes at the same location
|
|
|
|
//
|
|
|
|
// We should either resolve these to a single token, or drop them all.
|
|
|
|
// Our heuristics are:
|
|
|
|
//
|
|
|
|
// - token kinds that come with "dependent-name" modifiers are less reliable
|
|
|
|
// (these tend to be vague, like Type or Unknown)
|
|
|
|
// - if we have multiple equally reliable kinds, drop token rather than guess
|
|
|
|
// - take the union of modifiers from all tokens
|
|
|
|
//
|
|
|
|
// In particular, heuristically resolved dependent names get their heuristic
|
|
|
|
// kind, plus the dependent modifier.
|
2020-03-20 03:42:10 +08:00
|
|
|
llvm::Optional<HighlightingToken>
|
|
|
|
resolveConflict(ArrayRef<HighlightingToken> Tokens) {
|
|
|
|
if (Tokens.size() == 1)
|
|
|
|
return Tokens[0];
|
|
|
|
|
|
|
|
if (Tokens.size() != 2)
|
|
|
|
return llvm::None;
|
|
|
|
|
2021-01-30 08:12:36 +08:00
|
|
|
unsigned Priority1 = evaluateHighlightPriority(Tokens[0]);
|
|
|
|
unsigned Priority2 = evaluateHighlightPriority(Tokens[1]);
|
|
|
|
if (Priority1 == Priority2 && Tokens[0].Kind != Tokens[1].Kind)
|
2020-03-20 03:42:10 +08:00
|
|
|
return llvm::None;
|
2021-01-30 08:12:36 +08:00
|
|
|
auto Result = Priority1 > Priority2 ? Tokens[0] : Tokens[1];
|
|
|
|
Result.Modifiers = Tokens[0].Modifiers | Tokens[1].Modifiers;
|
|
|
|
return Result;
|
2020-03-20 03:42:10 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
/// Consumes source locations and maps them to text ranges for highlightings.
|
|
|
|
class HighlightingsBuilder {
|
2019-06-26 21:08:36 +08:00
|
|
|
public:
|
2020-03-01 23:04:07 +08:00
|
|
|
HighlightingsBuilder(const ParsedAST &AST)
|
|
|
|
: TB(AST.getTokens()), SourceMgr(AST.getSourceManager()),
|
|
|
|
LangOpts(AST.getLangOpts()) {}
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
|
2021-01-27 16:47:17 +08:00
|
|
|
HighlightingToken &addToken(SourceLocation Loc, HighlightingKind Kind) {
|
2020-03-01 23:04:07 +08:00
|
|
|
Loc = getHighlightableSpellingToken(Loc, SourceMgr);
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
if (Loc.isInvalid())
|
2021-03-22 18:18:18 +08:00
|
|
|
return InvalidHighlightingToken;
|
2020-03-01 23:04:07 +08:00
|
|
|
const auto *Tok = TB.spelledTokenAt(Loc);
|
|
|
|
assert(Tok);
|
2021-01-27 16:47:17 +08:00
|
|
|
return addToken(
|
|
|
|
halfOpenToRange(SourceMgr,
|
|
|
|
Tok->range(SourceMgr).toCharRange(SourceMgr)),
|
|
|
|
Kind);
|
|
|
|
}
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
|
2021-01-27 16:47:17 +08:00
|
|
|
HighlightingToken &addToken(Range R, HighlightingKind Kind) {
|
|
|
|
HighlightingToken HT;
|
|
|
|
HT.R = std::move(R);
|
|
|
|
HT.Kind = Kind;
|
|
|
|
Tokens.push_back(std::move(HT));
|
|
|
|
return Tokens.back();
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
}
|
|
|
|
|
2019-09-25 06:17:55 +08:00
|
|
|
std::vector<HighlightingToken> collect(ParsedAST &AST) && {
|
2019-07-15 23:08:27 +08:00
|
|
|
// Initializer lists can give duplicates of tokens, therefore all tokens
|
|
|
|
// must be deduplicated.
|
2019-08-01 16:08:44 +08:00
|
|
|
llvm::sort(Tokens);
|
2019-07-15 23:08:27 +08:00
|
|
|
auto Last = std::unique(Tokens.begin(), Tokens.end());
|
|
|
|
Tokens.erase(Last, Tokens.end());
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
|
2019-08-20 00:27:49 +08:00
|
|
|
// Macros can give tokens that have the same source range but conflicting
|
|
|
|
// kinds. In this case all tokens sharing this source range should be
|
|
|
|
// removed.
|
|
|
|
std::vector<HighlightingToken> NonConflicting;
|
|
|
|
NonConflicting.reserve(Tokens.size());
|
|
|
|
for (ArrayRef<HighlightingToken> TokRef = Tokens; !TokRef.empty();) {
|
|
|
|
ArrayRef<HighlightingToken> Conflicting =
|
|
|
|
TokRef.take_while([&](const HighlightingToken &T) {
|
|
|
|
// TokRef is guaranteed at least one element here because otherwise
|
|
|
|
// this predicate would never fire.
|
|
|
|
return T.R == TokRef.front().R;
|
|
|
|
});
|
2020-03-20 03:42:10 +08:00
|
|
|
if (auto Resolved = resolveConflict(Conflicting))
|
|
|
|
NonConflicting.push_back(*Resolved);
|
2019-08-20 00:27:49 +08:00
|
|
|
// TokRef[Conflicting.size()] is the next token with a different range (or
|
|
|
|
// the end of the Tokens).
|
|
|
|
TokRef = TokRef.drop_front(Conflicting.size());
|
|
|
|
}
|
2020-08-26 16:50:31 +08:00
|
|
|
const auto &SM = AST.getSourceManager();
|
2020-10-15 02:36:00 +08:00
|
|
|
StringRef MainCode = SM.getBufferOrFake(SM.getMainFileID()).getBuffer();
|
2020-08-26 16:50:31 +08:00
|
|
|
|
|
|
|
// Merge token stream with "inactive line" markers.
|
|
|
|
std::vector<HighlightingToken> WithInactiveLines;
|
|
|
|
auto SortedSkippedRanges = AST.getMacros().SkippedRanges;
|
|
|
|
llvm::sort(SortedSkippedRanges);
|
|
|
|
auto It = NonConflicting.begin();
|
|
|
|
for (const Range &R : SortedSkippedRanges) {
|
2019-09-25 06:17:55 +08:00
|
|
|
// Create one token for each line in the skipped range, so it works
|
|
|
|
// with line-based diffing.
|
|
|
|
assert(R.start.line <= R.end.line);
|
2020-07-10 05:56:06 +08:00
|
|
|
for (int Line = R.start.line; Line <= R.end.line; ++Line) {
|
2020-11-26 10:31:09 +08:00
|
|
|
// If the end of the inactive range is at the beginning
|
|
|
|
// of a line, that line is not inactive.
|
|
|
|
if (Line == R.end.line && R.end.character == 0)
|
|
|
|
continue;
|
2020-08-26 16:50:31 +08:00
|
|
|
// Copy tokens before the inactive line
|
|
|
|
for (; It != NonConflicting.end() && It->R.start.line < Line; ++It)
|
|
|
|
WithInactiveLines.push_back(std::move(*It));
|
|
|
|
// Add a token for the inactive line itself.
|
|
|
|
auto StartOfLine = positionToOffset(MainCode, Position{Line, 0});
|
|
|
|
if (StartOfLine) {
|
|
|
|
StringRef LineText =
|
|
|
|
MainCode.drop_front(*StartOfLine).take_until([](char C) {
|
|
|
|
return C == '\n';
|
|
|
|
});
|
2021-01-27 16:47:17 +08:00
|
|
|
HighlightingToken HT;
|
|
|
|
WithInactiveLines.emplace_back();
|
|
|
|
WithInactiveLines.back().Kind = HighlightingKind::InactiveCode;
|
|
|
|
WithInactiveLines.back().R.start.line = Line;
|
|
|
|
WithInactiveLines.back().R.end.line = Line;
|
|
|
|
WithInactiveLines.back().R.end.character =
|
|
|
|
static_cast<int>(lspLength(LineText));
|
2020-08-26 16:50:31 +08:00
|
|
|
} else {
|
|
|
|
elog("Failed to convert position to offset: {0}",
|
|
|
|
StartOfLine.takeError());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip any other tokens on the inactive line. e.g.
|
|
|
|
// `#ifndef Foo` is considered as part of an inactive region when Foo is
|
|
|
|
// defined, and there is a Foo macro token.
|
|
|
|
// FIXME: we should reduce the scope of the inactive region to not
|
|
|
|
// include the directive itself.
|
|
|
|
while (It != NonConflicting.end() && It->R.start.line == Line)
|
|
|
|
++It;
|
2019-09-25 06:17:55 +08:00
|
|
|
}
|
|
|
|
}
|
2020-08-26 16:50:31 +08:00
|
|
|
// Copy tokens after the last inactive line
|
|
|
|
for (; It != NonConflicting.end(); ++It)
|
|
|
|
WithInactiveLines.push_back(std::move(*It));
|
|
|
|
return WithInactiveLines;
|
2019-06-26 21:08:36 +08:00
|
|
|
}
|
|
|
|
|
2021-03-22 14:43:41 +08:00
|
|
|
const HeuristicResolver *getResolver() const { return Resolver; }
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
private:
|
2020-03-01 23:04:07 +08:00
|
|
|
const syntax::TokenBuffer &TB;
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
const SourceManager &SourceMgr;
|
|
|
|
const LangOptions &LangOpts;
|
|
|
|
std::vector<HighlightingToken> Tokens;
|
2021-03-22 14:43:41 +08:00
|
|
|
const HeuristicResolver *Resolver;
|
2021-03-22 18:18:18 +08:00
|
|
|
// returned from addToken(InvalidLoc)
|
|
|
|
HighlightingToken InvalidHighlightingToken;
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
};
|
2019-07-05 21:06:03 +08:00
|
|
|
|
2021-01-30 06:18:34 +08:00
|
|
|
llvm::Optional<HighlightingModifier> scopeModifier(const NamedDecl *D) {
|
|
|
|
const DeclContext *DC = D->getDeclContext();
|
|
|
|
// Injected "Foo" within the class "Foo" has file scope, not class scope.
|
|
|
|
if (auto *R = dyn_cast_or_null<RecordDecl>(D))
|
|
|
|
if (R->isInjectedClassName())
|
|
|
|
DC = DC->getParent();
|
|
|
|
// Lambda captures are considered function scope, not class scope.
|
|
|
|
if (llvm::isa<FieldDecl>(D))
|
|
|
|
if (const auto *RD = llvm::dyn_cast<RecordDecl>(DC))
|
|
|
|
if (RD->isLambda())
|
|
|
|
return HighlightingModifier::FunctionScope;
|
|
|
|
// Walk up the DeclContext hierarchy until we find something interesting.
|
|
|
|
for (; !DC->isFileContext(); DC = DC->getParent()) {
|
|
|
|
if (DC->isFunctionOrMethod())
|
|
|
|
return HighlightingModifier::FunctionScope;
|
|
|
|
if (DC->isRecord())
|
|
|
|
return HighlightingModifier::ClassScope;
|
|
|
|
}
|
|
|
|
// Some template parameters (e.g. those for variable templates) don't have
|
|
|
|
// meaningful DeclContexts. That doesn't mean they're global!
|
|
|
|
if (DC->isTranslationUnit() && D->isTemplateParameter())
|
|
|
|
return llvm::None;
|
|
|
|
// ExternalLinkage threshold could be tweaked, e.g. module-visible as global.
|
|
|
|
if (D->getLinkageInternal() < ExternalLinkage)
|
|
|
|
return HighlightingModifier::FileScope;
|
|
|
|
return HighlightingModifier::GlobalScope;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Optional<HighlightingModifier> scopeModifier(const Type *T) {
|
|
|
|
if (!T)
|
|
|
|
return llvm::None;
|
|
|
|
if (T->isBuiltinType())
|
|
|
|
return HighlightingModifier::GlobalScope;
|
|
|
|
if (auto *TD = dyn_cast<TemplateTypeParmType>(T))
|
|
|
|
return scopeModifier(TD->getDecl());
|
|
|
|
if (auto *TD = T->getAsTagDecl())
|
|
|
|
return scopeModifier(TD);
|
|
|
|
return llvm::None;
|
|
|
|
}
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
/// Produces highlightings, which are not captured by findExplicitReferences,
|
|
|
|
/// e.g. highlights dependent names and 'auto' as the underlying type.
|
|
|
|
class CollectExtraHighlightings
|
|
|
|
: public RecursiveASTVisitor<CollectExtraHighlightings> {
|
|
|
|
public:
|
|
|
|
CollectExtraHighlightings(HighlightingsBuilder &H) : H(H) {}
|
2019-10-28 20:42:20 +08:00
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) {
|
2021-03-22 14:43:41 +08:00
|
|
|
if (auto K = kindForType(L.getTypePtr(), H.getResolver())) {
|
2021-01-30 06:18:34 +08:00
|
|
|
auto &Tok = H.addToken(L.getBeginLoc(), *K)
|
|
|
|
.addModifier(HighlightingModifier::Deduced);
|
|
|
|
if (auto Mod = scopeModifier(L.getTypePtr()))
|
|
|
|
Tok.addModifier(*Mod);
|
2021-04-30 01:03:10 +08:00
|
|
|
if (isDefaultLibrary(L.getTypePtr()))
|
|
|
|
Tok.addModifier(HighlightingModifier::DefaultLibrary);
|
2021-01-30 06:18:34 +08:00
|
|
|
}
|
2019-07-16 21:23:12 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
bool VisitDeclaratorDecl(DeclaratorDecl *D) {
|
|
|
|
auto *AT = D->getType()->getContainedAutoType();
|
|
|
|
if (!AT)
|
|
|
|
return true;
|
2021-03-22 14:43:41 +08:00
|
|
|
if (auto K = kindForType(AT->getDeducedType().getTypePtrOrNull(),
|
|
|
|
H.getResolver())) {
|
2021-01-30 06:18:34 +08:00
|
|
|
auto &Tok = H.addToken(D->getTypeSpecStartLoc(), *K)
|
|
|
|
.addModifier(HighlightingModifier::Deduced);
|
2021-04-30 01:03:10 +08:00
|
|
|
const Type *Deduced = AT->getDeducedType().getTypePtrOrNull();
|
|
|
|
if (auto Mod = scopeModifier(Deduced))
|
2021-01-30 06:18:34 +08:00
|
|
|
Tok.addModifier(*Mod);
|
2021-04-30 01:03:10 +08:00
|
|
|
if (isDefaultLibrary(Deduced))
|
|
|
|
Tok.addModifier(HighlightingModifier::DefaultLibrary);
|
2021-01-30 06:18:34 +08:00
|
|
|
}
|
2019-07-18 17:56:38 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-02-28 05:08:07 +08:00
|
|
|
// We handle objective-C selectors specially, because one reference can
|
|
|
|
// cover several non-contiguous tokens.
|
|
|
|
void highlightObjCSelector(const ArrayRef<SourceLocation> &Locs, bool Decl,
|
2021-04-30 01:03:10 +08:00
|
|
|
bool Class, bool DefaultLibrary) {
|
2021-02-28 05:08:07 +08:00
|
|
|
HighlightingKind Kind =
|
|
|
|
Class ? HighlightingKind::StaticMethod : HighlightingKind::Method;
|
|
|
|
for (SourceLocation Part : Locs) {
|
|
|
|
auto &Tok =
|
|
|
|
H.addToken(Part, Kind).addModifier(HighlightingModifier::ClassScope);
|
|
|
|
if (Decl)
|
|
|
|
Tok.addModifier(HighlightingModifier::Declaration);
|
|
|
|
if (Class)
|
|
|
|
Tok.addModifier(HighlightingModifier::Static);
|
2021-04-30 01:03:10 +08:00
|
|
|
if (DefaultLibrary)
|
|
|
|
Tok.addModifier(HighlightingModifier::DefaultLibrary);
|
2021-02-28 05:08:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
|
|
|
|
llvm::SmallVector<SourceLocation> Locs;
|
|
|
|
OMD->getSelectorLocs(Locs);
|
2021-04-30 01:03:10 +08:00
|
|
|
highlightObjCSelector(Locs, /*Decl=*/true, OMD->isClassMethod(),
|
|
|
|
isDefaultLibrary(OMD));
|
2021-02-28 05:08:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VisitObjCMessageExpr(ObjCMessageExpr *OME) {
|
|
|
|
llvm::SmallVector<SourceLocation> Locs;
|
|
|
|
OME->getSelectorLocs(Locs);
|
2021-04-30 01:03:10 +08:00
|
|
|
bool DefaultLibrary = false;
|
|
|
|
if (ObjCMethodDecl *OMD = OME->getMethodDecl())
|
|
|
|
DefaultLibrary = isDefaultLibrary(OMD);
|
|
|
|
highlightObjCSelector(Locs, /*Decl=*/false, OME->isClassMessage(),
|
|
|
|
DefaultLibrary);
|
2021-02-28 05:08:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-11 22:16:19 +08:00
|
|
|
// Objective-C allows you to use property syntax `self.prop` as sugar for
|
|
|
|
// `[self prop]` and `[self setProp:]` when there's no explicit `@property`
|
|
|
|
// for `prop` as well as for class properties. We treat this like a property
|
|
|
|
// even though semantically it's equivalent to a method expression.
|
|
|
|
void highlightObjCImplicitPropertyRef(const ObjCMethodDecl *OMD,
|
|
|
|
SourceLocation Loc) {
|
|
|
|
auto &Tok = H.addToken(Loc, HighlightingKind::Field)
|
|
|
|
.addModifier(HighlightingModifier::ClassScope);
|
|
|
|
if (OMD->isClassMethod())
|
|
|
|
Tok.addModifier(HighlightingModifier::Static);
|
|
|
|
if (isDefaultLibrary(OMD))
|
|
|
|
Tok.addModifier(HighlightingModifier::DefaultLibrary);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *OPRE) {
|
|
|
|
// We need to handle implicit properties here since they will appear to
|
|
|
|
// reference `ObjCMethodDecl` via an implicit `ObjCMessageExpr`, so normal
|
|
|
|
// highlighting will not work.
|
|
|
|
if (!OPRE->isImplicitProperty())
|
|
|
|
return true;
|
|
|
|
// A single property expr can reference both a getter and setter, but we can
|
|
|
|
// only provide a single semantic token, so prefer the getter. In most cases
|
|
|
|
// the end result should be the same, although it's technically possible
|
|
|
|
// that the user defines a setter for a system SDK.
|
|
|
|
if (OPRE->isMessagingGetter()) {
|
|
|
|
highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertyGetter(),
|
|
|
|
OPRE->getLocation());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (OPRE->isMessagingSetter()) {
|
|
|
|
highlightObjCImplicitPropertyRef(OPRE->getImplicitPropertySetter(),
|
|
|
|
OPRE->getLocation());
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
bool VisitOverloadExpr(OverloadExpr *E) {
|
|
|
|
if (!E->decls().empty())
|
|
|
|
return true; // handled by findExplicitReferences.
|
2021-01-30 08:12:36 +08:00
|
|
|
auto &Tok = H.addToken(E->getNameLoc(), HighlightingKind::Unknown)
|
|
|
|
.addModifier(HighlightingModifier::DependentName);
|
2021-01-30 06:18:34 +08:00
|
|
|
if (llvm::isa<UnresolvedMemberExpr>(E))
|
|
|
|
Tok.addModifier(HighlightingModifier::ClassScope);
|
|
|
|
// other case is UnresolvedLookupExpr, scope is unknown.
|
2019-07-18 17:56:38 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
|
2021-01-30 08:12:36 +08:00
|
|
|
H.addToken(E->getMemberNameInfo().getLoc(), HighlightingKind::Unknown)
|
|
|
|
.addModifier(HighlightingModifier::DependentName)
|
2021-01-30 06:18:34 +08:00
|
|
|
.addModifier(HighlightingModifier::ClassScope);
|
2019-10-28 18:31:06 +08:00
|
|
|
return true;
|
2019-09-17 00:16:03 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
|
2021-01-30 08:12:36 +08:00
|
|
|
H.addToken(E->getNameInfo().getLoc(), HighlightingKind::Unknown)
|
|
|
|
.addModifier(HighlightingModifier::DependentName)
|
2021-01-30 06:18:34 +08:00
|
|
|
.addModifier(HighlightingModifier::ClassScope);
|
2019-09-17 00:16:03 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-28 18:31:06 +08:00
|
|
|
bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
|
2021-01-30 08:12:36 +08:00
|
|
|
H.addToken(L.getNameLoc(), HighlightingKind::Type)
|
|
|
|
.addModifier(HighlightingModifier::DependentName)
|
2021-01-30 06:18:34 +08:00
|
|
|
.addModifier(HighlightingModifier::ClassScope);
|
2019-08-12 15:45:12 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-06 03:28:56 +08:00
|
|
|
bool VisitDependentTemplateSpecializationTypeLoc(
|
|
|
|
DependentTemplateSpecializationTypeLoc L) {
|
2021-01-30 08:12:36 +08:00
|
|
|
H.addToken(L.getTemplateNameLoc(), HighlightingKind::Type)
|
|
|
|
.addModifier(HighlightingModifier::DependentName)
|
2021-01-30 06:18:34 +08:00
|
|
|
.addModifier(HighlightingModifier::ClassScope);
|
2019-12-06 03:28:56 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-08-05 11:33:41 +08:00
|
|
|
bool TraverseTemplateArgumentLoc(TemplateArgumentLoc L) {
|
2021-01-30 08:12:36 +08:00
|
|
|
// Handle template template arguments only (other arguments are handled by
|
|
|
|
// their Expr, TypeLoc etc values).
|
|
|
|
if (L.getArgument().getKind() != TemplateArgument::Template &&
|
|
|
|
L.getArgument().getKind() != TemplateArgument::TemplateExpansion)
|
|
|
|
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
|
|
|
|
|
|
|
|
TemplateName N = L.getArgument().getAsTemplateOrTemplatePattern();
|
|
|
|
switch (N.getKind()) {
|
|
|
|
case TemplateName::OverloadedTemplate:
|
|
|
|
// Template template params must always be class templates.
|
|
|
|
// Don't bother to try to work out the scope here.
|
|
|
|
H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class);
|
|
|
|
break;
|
|
|
|
case TemplateName::DependentTemplate:
|
|
|
|
case TemplateName::AssumedTemplate:
|
|
|
|
H.addToken(L.getTemplateNameLoc(), HighlightingKind::Class)
|
|
|
|
.addModifier(HighlightingModifier::DependentName);
|
2020-08-05 11:33:41 +08:00
|
|
|
break;
|
2021-01-30 08:12:36 +08:00
|
|
|
case TemplateName::Template:
|
|
|
|
case TemplateName::QualifiedTemplate:
|
|
|
|
case TemplateName::SubstTemplateTemplateParm:
|
|
|
|
case TemplateName::SubstTemplateTemplateParmPack:
|
|
|
|
// Names that could be resolved to a TemplateDecl are handled elsewhere.
|
2020-08-05 11:33:41 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
|
|
|
|
}
|
|
|
|
|
2019-12-06 03:28:56 +08:00
|
|
|
// findExplicitReferences will walk nested-name-specifiers and
|
|
|
|
// find anything that can be resolved to a Decl. However, non-leaf
|
|
|
|
// components of nested-name-specifiers which are dependent names
|
|
|
|
// (kind "Identifier") cannot be resolved to a decl, so we visit
|
|
|
|
// them here.
|
|
|
|
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) {
|
|
|
|
if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) {
|
|
|
|
if (NNS->getKind() == NestedNameSpecifier::Identifier)
|
2021-01-30 08:12:36 +08:00
|
|
|
H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type)
|
|
|
|
.addModifier(HighlightingModifier::DependentName)
|
2021-01-30 06:18:34 +08:00
|
|
|
.addModifier(HighlightingModifier::ClassScope);
|
2019-12-06 03:28:56 +08:00
|
|
|
}
|
|
|
|
return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q);
|
|
|
|
}
|
|
|
|
|
2019-08-12 15:45:12 +08:00
|
|
|
private:
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
HighlightingsBuilder &H;
|
2019-06-26 21:08:36 +08:00
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) {
|
|
|
|
auto &C = AST.getASTContext();
|
|
|
|
// Add highlightings for AST nodes.
|
2020-03-01 23:04:07 +08:00
|
|
|
HighlightingsBuilder Builder(AST);
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
// Highlight 'decltype' and 'auto' as their underlying types.
|
|
|
|
CollectExtraHighlightings(Builder).TraverseAST(C);
|
|
|
|
// Highlight all decls and references coming from the AST.
|
2021-01-18 15:58:43 +08:00
|
|
|
findExplicitReferences(
|
|
|
|
C,
|
|
|
|
[&](ReferenceLoc R) {
|
|
|
|
for (const NamedDecl *Decl : R.Targets) {
|
|
|
|
if (!canHighlightName(Decl->getDeclName()))
|
|
|
|
continue;
|
2021-03-22 14:43:41 +08:00
|
|
|
auto Kind = kindForDecl(Decl, AST.getHeuristicResolver());
|
2021-01-18 15:58:43 +08:00
|
|
|
if (!Kind)
|
|
|
|
continue;
|
|
|
|
auto &Tok = Builder.addToken(R.NameLoc, *Kind);
|
|
|
|
|
|
|
|
// The attribute tests don't want to look at the template.
|
|
|
|
if (auto *TD = dyn_cast<TemplateDecl>(Decl)) {
|
|
|
|
if (auto *Templated = TD->getTemplatedDecl())
|
|
|
|
Decl = Templated;
|
|
|
|
}
|
|
|
|
if (auto Mod = scopeModifier(Decl))
|
|
|
|
Tok.addModifier(*Mod);
|
|
|
|
if (isConst(Decl))
|
|
|
|
Tok.addModifier(HighlightingModifier::Readonly);
|
|
|
|
if (isStatic(Decl))
|
|
|
|
Tok.addModifier(HighlightingModifier::Static);
|
|
|
|
if (isAbstract(Decl))
|
|
|
|
Tok.addModifier(HighlightingModifier::Abstract);
|
2021-08-04 10:53:01 +08:00
|
|
|
if (isVirtual(Decl))
|
|
|
|
Tok.addModifier(HighlightingModifier::Virtual);
|
2021-03-22 14:13:53 +08:00
|
|
|
if (isDependent(Decl))
|
|
|
|
Tok.addModifier(HighlightingModifier::DependentName);
|
2021-04-30 01:03:10 +08:00
|
|
|
if (isDefaultLibrary(Decl))
|
|
|
|
Tok.addModifier(HighlightingModifier::DefaultLibrary);
|
2021-01-18 15:58:43 +08:00
|
|
|
if (Decl->isDeprecated())
|
|
|
|
Tok.addModifier(HighlightingModifier::Deprecated);
|
2021-03-22 14:13:53 +08:00
|
|
|
// Do not treat an UnresolvedUsingValueDecl as a declaration.
|
|
|
|
// It's more common to think of it as a reference to the
|
|
|
|
// underlying declaration.
|
|
|
|
if (R.IsDecl && !isa<UnresolvedUsingValueDecl>(Decl))
|
2021-01-18 15:58:43 +08:00
|
|
|
Tok.addModifier(HighlightingModifier::Declaration);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
AST.getHeuristicResolver());
|
2019-11-07 19:14:38 +08:00
|
|
|
// Add highlightings for macro references.
|
2021-01-27 16:47:17 +08:00
|
|
|
auto AddMacro = [&](const MacroOccurrence &M) {
|
|
|
|
auto &T = Builder.addToken(M.Rng, HighlightingKind::Macro);
|
2021-01-30 06:18:34 +08:00
|
|
|
T.addModifier(HighlightingModifier::GlobalScope);
|
2021-01-27 16:47:17 +08:00
|
|
|
if (M.IsDefinition)
|
|
|
|
T.addModifier(HighlightingModifier::Declaration);
|
|
|
|
};
|
|
|
|
for (const auto &SIDToRefs : AST.getMacros().MacroRefs)
|
2019-11-07 19:14:38 +08:00
|
|
|
for (const auto &M : SIDToRefs.second)
|
2021-01-27 16:47:17 +08:00
|
|
|
AddMacro(M);
|
2019-11-07 19:14:38 +08:00
|
|
|
for (const auto &M : AST.getMacros().UnknownMacros)
|
2021-01-27 16:47:17 +08:00
|
|
|
AddMacro(M);
|
2019-11-07 19:14:38 +08:00
|
|
|
|
2019-09-25 06:17:55 +08:00
|
|
|
return std::move(Builder).collect(AST);
|
[clangd] Implement semantic highlightings via findExplicitReferences
Summary:
To keep the logic of finding locations of interesting AST nodes in one
place.
The advantage is better coverage of various AST nodes, both now and in
the future: as new nodes get added to `findExplicitReferences`, semantic
highlighting will automatically pick them up.
The drawback of this change is that we have to traverse declarations
inside our file twice in order to highlight dependent names, 'auto'
and 'decltype'. Hopefully, this should not affect the actual latency
too much, most time should be spent in building the AST and not
traversing it.
Reviewers: hokein
Reviewed By: hokein
Subscribers: nridge, merge_guards_bot, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69673
2019-11-06 02:06:12 +08:00
|
|
|
}
|
|
|
|
|
2019-09-09 16:47:05 +08:00
|
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingKind K) {
|
|
|
|
switch (K) {
|
|
|
|
case HighlightingKind::Variable:
|
|
|
|
return OS << "Variable";
|
|
|
|
case HighlightingKind::LocalVariable:
|
|
|
|
return OS << "LocalVariable";
|
|
|
|
case HighlightingKind::Parameter:
|
|
|
|
return OS << "Parameter";
|
|
|
|
case HighlightingKind::Function:
|
|
|
|
return OS << "Function";
|
|
|
|
case HighlightingKind::Method:
|
|
|
|
return OS << "Method";
|
|
|
|
case HighlightingKind::StaticMethod:
|
|
|
|
return OS << "StaticMethod";
|
|
|
|
case HighlightingKind::Field:
|
|
|
|
return OS << "Field";
|
|
|
|
case HighlightingKind::StaticField:
|
|
|
|
return OS << "StaticField";
|
|
|
|
case HighlightingKind::Class:
|
|
|
|
return OS << "Class";
|
2021-02-28 05:08:07 +08:00
|
|
|
case HighlightingKind::Interface:
|
|
|
|
return OS << "Interface";
|
2019-09-09 16:47:05 +08:00
|
|
|
case HighlightingKind::Enum:
|
|
|
|
return OS << "Enum";
|
|
|
|
case HighlightingKind::EnumConstant:
|
|
|
|
return OS << "EnumConstant";
|
2019-09-09 22:33:10 +08:00
|
|
|
case HighlightingKind::Typedef:
|
|
|
|
return OS << "Typedef";
|
2021-01-30 08:12:36 +08:00
|
|
|
case HighlightingKind::Type:
|
|
|
|
return OS << "Type";
|
|
|
|
case HighlightingKind::Unknown:
|
|
|
|
return OS << "Unknown";
|
2019-09-09 16:47:05 +08:00
|
|
|
case HighlightingKind::Namespace:
|
|
|
|
return OS << "Namespace";
|
|
|
|
case HighlightingKind::TemplateParameter:
|
|
|
|
return OS << "TemplateParameter";
|
2020-01-22 02:21:08 +08:00
|
|
|
case HighlightingKind::Concept:
|
|
|
|
return OS << "Concept";
|
2019-09-09 16:47:05 +08:00
|
|
|
case HighlightingKind::Primitive:
|
|
|
|
return OS << "Primitive";
|
|
|
|
case HighlightingKind::Macro:
|
|
|
|
return OS << "Macro";
|
2019-09-25 06:17:55 +08:00
|
|
|
case HighlightingKind::InactiveCode:
|
|
|
|
return OS << "InactiveCode";
|
2019-09-09 16:47:05 +08:00
|
|
|
}
|
2019-09-09 16:57:17 +08:00
|
|
|
llvm_unreachable("invalid HighlightingKind");
|
2019-09-09 16:47:05 +08:00
|
|
|
}
|
2021-01-27 16:47:17 +08:00
|
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, HighlightingModifier K) {
|
|
|
|
switch (K) {
|
|
|
|
case HighlightingModifier::Declaration:
|
|
|
|
return OS << "decl"; // abbrevation for common case
|
|
|
|
default:
|
|
|
|
return OS << toSemanticTokenModifier(K);
|
|
|
|
}
|
|
|
|
}
|
2019-09-09 16:47:05 +08:00
|
|
|
|
2019-08-01 16:08:44 +08:00
|
|
|
bool operator==(const HighlightingToken &L, const HighlightingToken &R) {
|
2021-01-27 16:47:17 +08:00
|
|
|
return std::tie(L.R, L.Kind, L.Modifiers) ==
|
|
|
|
std::tie(R.R, R.Kind, R.Modifiers);
|
2019-08-01 16:08:44 +08:00
|
|
|
}
|
|
|
|
bool operator<(const HighlightingToken &L, const HighlightingToken &R) {
|
2021-01-27 16:47:17 +08:00
|
|
|
return std::tie(L.R, L.Kind, R.Modifiers) <
|
|
|
|
std::tie(R.R, R.Kind, R.Modifiers);
|
2019-08-01 16:08:44 +08:00
|
|
|
}
|
2019-06-26 21:08:36 +08:00
|
|
|
|
2020-03-24 09:24:47 +08:00
|
|
|
std::vector<SemanticToken>
|
|
|
|
toSemanticTokens(llvm::ArrayRef<HighlightingToken> Tokens) {
|
|
|
|
assert(std::is_sorted(Tokens.begin(), Tokens.end()));
|
|
|
|
std::vector<SemanticToken> Result;
|
|
|
|
const HighlightingToken *Last = nullptr;
|
|
|
|
for (const HighlightingToken &Tok : Tokens) {
|
|
|
|
Result.emplace_back();
|
|
|
|
SemanticToken &Out = Result.back();
|
|
|
|
// deltaStart/deltaLine are relative if possible.
|
|
|
|
if (Last) {
|
|
|
|
assert(Tok.R.start.line >= Last->R.start.line);
|
|
|
|
Out.deltaLine = Tok.R.start.line - Last->R.start.line;
|
|
|
|
if (Out.deltaLine == 0) {
|
|
|
|
assert(Tok.R.start.character >= Last->R.start.character);
|
|
|
|
Out.deltaStart = Tok.R.start.character - Last->R.start.character;
|
|
|
|
} else {
|
|
|
|
Out.deltaStart = Tok.R.start.character;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Out.deltaLine = Tok.R.start.line;
|
|
|
|
Out.deltaStart = Tok.R.start.character;
|
|
|
|
}
|
|
|
|
assert(Tok.R.end.line == Tok.R.start.line);
|
|
|
|
Out.length = Tok.R.end.character - Tok.R.start.character;
|
|
|
|
Out.tokenType = static_cast<unsigned>(Tok.Kind);
|
2021-01-27 16:47:17 +08:00
|
|
|
Out.tokenModifiers = Tok.Modifiers;
|
2020-03-24 09:24:47 +08:00
|
|
|
|
|
|
|
Last = &Tok;
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
llvm::StringRef toSemanticTokenType(HighlightingKind Kind) {
|
|
|
|
switch (Kind) {
|
|
|
|
case HighlightingKind::Variable:
|
|
|
|
case HighlightingKind::LocalVariable:
|
|
|
|
case HighlightingKind::StaticField:
|
|
|
|
return "variable";
|
|
|
|
case HighlightingKind::Parameter:
|
|
|
|
return "parameter";
|
|
|
|
case HighlightingKind::Function:
|
|
|
|
return "function";
|
|
|
|
case HighlightingKind::Method:
|
2020-11-26 04:31:18 +08:00
|
|
|
return "method";
|
2020-03-24 09:24:47 +08:00
|
|
|
case HighlightingKind::StaticMethod:
|
2020-11-26 04:31:18 +08:00
|
|
|
// FIXME: better method with static modifier?
|
2020-03-24 09:24:47 +08:00
|
|
|
return "function";
|
|
|
|
case HighlightingKind::Field:
|
2020-11-21 03:51:58 +08:00
|
|
|
return "property";
|
2020-03-24 09:24:47 +08:00
|
|
|
case HighlightingKind::Class:
|
|
|
|
return "class";
|
2021-02-28 05:08:07 +08:00
|
|
|
case HighlightingKind::Interface:
|
|
|
|
return "interface";
|
2020-03-24 09:24:47 +08:00
|
|
|
case HighlightingKind::Enum:
|
|
|
|
return "enum";
|
|
|
|
case HighlightingKind::EnumConstant:
|
2020-12-11 22:46:12 +08:00
|
|
|
return "enumMember";
|
2020-03-24 09:24:47 +08:00
|
|
|
case HighlightingKind::Typedef:
|
2021-01-30 08:12:36 +08:00
|
|
|
case HighlightingKind::Type:
|
2020-03-24 09:24:47 +08:00
|
|
|
return "type";
|
2021-01-30 08:12:36 +08:00
|
|
|
case HighlightingKind::Unknown:
|
|
|
|
return "unknown"; // nonstandard
|
2020-03-24 09:24:47 +08:00
|
|
|
case HighlightingKind::Namespace:
|
|
|
|
return "namespace";
|
|
|
|
case HighlightingKind::TemplateParameter:
|
|
|
|
return "typeParameter";
|
|
|
|
case HighlightingKind::Concept:
|
|
|
|
return "concept"; // nonstandard
|
|
|
|
case HighlightingKind::Primitive:
|
|
|
|
return "type";
|
|
|
|
case HighlightingKind::Macro:
|
|
|
|
return "macro";
|
|
|
|
case HighlightingKind::InactiveCode:
|
|
|
|
return "comment";
|
|
|
|
}
|
2020-04-01 21:08:25 +08:00
|
|
|
llvm_unreachable("unhandled HighlightingKind");
|
2020-03-24 09:24:47 +08:00
|
|
|
}
|
|
|
|
|
2021-01-27 16:47:17 +08:00
|
|
|
llvm::StringRef toSemanticTokenModifier(HighlightingModifier Modifier) {
|
|
|
|
switch (Modifier) {
|
|
|
|
case HighlightingModifier::Declaration:
|
|
|
|
return "declaration";
|
|
|
|
case HighlightingModifier::Deprecated:
|
|
|
|
return "deprecated";
|
|
|
|
case HighlightingModifier::Readonly:
|
|
|
|
return "readonly";
|
|
|
|
case HighlightingModifier::Static:
|
|
|
|
return "static";
|
|
|
|
case HighlightingModifier::Deduced:
|
|
|
|
return "deduced"; // nonstandard
|
|
|
|
case HighlightingModifier::Abstract:
|
|
|
|
return "abstract";
|
2021-08-04 10:53:01 +08:00
|
|
|
case HighlightingModifier::Virtual:
|
|
|
|
return "virtual";
|
2021-01-30 08:12:36 +08:00
|
|
|
case HighlightingModifier::DependentName:
|
|
|
|
return "dependentName"; // nonstandard
|
2021-04-30 01:03:10 +08:00
|
|
|
case HighlightingModifier::DefaultLibrary:
|
|
|
|
return "defaultLibrary";
|
2021-01-30 06:18:34 +08:00
|
|
|
case HighlightingModifier::FunctionScope:
|
|
|
|
return "functionScope"; // nonstandard
|
|
|
|
case HighlightingModifier::ClassScope:
|
|
|
|
return "classScope"; // nonstandard
|
|
|
|
case HighlightingModifier::FileScope:
|
|
|
|
return "fileScope"; // nonstandard
|
|
|
|
case HighlightingModifier::GlobalScope:
|
|
|
|
return "globalScope"; // nonstandard
|
2021-01-27 16:47:17 +08:00
|
|
|
}
|
2021-01-30 06:18:34 +08:00
|
|
|
llvm_unreachable("unhandled HighlightingModifier");
|
2021-01-27 16:47:17 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
std::vector<SemanticTokensEdit>
|
|
|
|
diffTokens(llvm::ArrayRef<SemanticToken> Old,
|
|
|
|
llvm::ArrayRef<SemanticToken> New) {
|
|
|
|
// For now, just replace everything from the first-last modification.
|
|
|
|
// FIXME: use a real diff instead, this is bad with include-insertion.
|
|
|
|
|
|
|
|
unsigned Offset = 0;
|
|
|
|
while (!Old.empty() && !New.empty() && Old.front() == New.front()) {
|
|
|
|
++Offset;
|
|
|
|
Old = Old.drop_front();
|
|
|
|
New = New.drop_front();
|
|
|
|
}
|
|
|
|
while (!Old.empty() && !New.empty() && Old.back() == New.back()) {
|
|
|
|
Old = Old.drop_back();
|
|
|
|
New = New.drop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Old.empty() && New.empty())
|
|
|
|
return {};
|
|
|
|
SemanticTokensEdit Edit;
|
|
|
|
Edit.startToken = Offset;
|
|
|
|
Edit.deleteTokens = Old.size();
|
|
|
|
Edit.tokens = New;
|
|
|
|
return {std::move(Edit)};
|
|
|
|
}
|
|
|
|
|
2019-06-26 21:08:36 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|