[clangd] Added highlightings for namespace specifiers.

Summary: Added highlightings for namespace specifiers.

Reviewers: hokein, sammccall, ilya-biryukov

Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D64492

llvm-svn: 365745
This commit is contained in:
Johan Vikstrom 2019-07-11 09:29:16 +00:00
parent 962524070a
commit b6a74e33c3
4 changed files with 72 additions and 11 deletions

View File

@ -11,8 +11,6 @@
#include "Protocol.h" #include "Protocol.h"
#include "SourceCode.h" #include "SourceCode.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/RecursiveASTVisitor.h"
namespace clang { namespace clang {
@ -36,7 +34,21 @@ public:
return Tokens; return Tokens;
} }
bool VisitNamespaceAliasDecl(NamespaceAliasDecl *NAD) {
// The target namespace of an alias can not be found in any other way.
addToken(NAD->getTargetNameLoc(), HighlightingKind::Namespace);
return true;
}
bool VisitNamedDecl(NamedDecl *ND) { bool VisitNamedDecl(NamedDecl *ND) {
// UsingDirectiveDecl's namespaces do not show up anywhere else in the
// Visit/Traverse mehods. But they should also be highlighted as a
// namespace.
if (const auto *UD = dyn_cast<UsingDirectiveDecl>(ND)) {
addToken(UD->getIdentLocation(), HighlightingKind::Namespace);
return true;
}
// Constructors' TypeLoc has a TypePtr that is a FunctionProtoType. It has // Constructors' TypeLoc has a TypePtr that is a FunctionProtoType. It has
// no tag decl and therefore constructors must be gotten as NamedDecls // no tag decl and therefore constructors must be gotten as NamedDecls
// instead. // instead.
@ -65,17 +77,28 @@ public:
bool VisitTypeLoc(TypeLoc &TL) { bool VisitTypeLoc(TypeLoc &TL) {
// This check is for not getting two entries when there are anonymous // This check is for not getting two entries when there are anonymous
// structs. It also makes us not highlight namespace qualifiers. For // structs. It also makes us not highlight certain namespace qualifiers
// elaborated types the actual type is highlighted as an inner TypeLoc. // twice. For elaborated types the actual type is highlighted as an inner
// TypeLoc.
if (TL.getTypeLocClass() == TypeLoc::TypeLocClass::Elaborated) if (TL.getTypeLocClass() == TypeLoc::TypeLocClass::Elaborated)
return true; return true;
if (const Type *TP = TL.getTypePtr()) if (const Type *TP = TL.getTypePtr())
if (const TagDecl *TD = TP->getAsTagDecl()) if (const TagDecl *TD = TP->getAsTagDecl())
addToken(TL.getBeginLoc(), TD); addToken(TL.getBeginLoc(), TD);
return true; return true;
} }
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
if (NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier())
if (NNS->getKind() == NestedNameSpecifier::Namespace ||
NNS->getKind() == NestedNameSpecifier::NamespaceAlias)
addToken(NNSLoc.getLocalBeginLoc(), HighlightingKind::Namespace);
return RecursiveASTVisitor<
HighlightingTokenCollector>::TraverseNestedNameSpecifierLoc(NNSLoc);
}
private: private:
void addToken(SourceLocation Loc, const NamedDecl *D) { void addToken(SourceLocation Loc, const NamedDecl *D) {
if (D->getDeclName().isIdentifier() && D->getName().empty()) if (D->getDeclName().isIdentifier() && D->getName().empty())
@ -104,6 +127,14 @@ private:
addToken(Loc, HighlightingKind::Function); addToken(Loc, HighlightingKind::Function);
return; return;
} }
if (isa<NamespaceDecl>(D)) {
addToken(Loc, HighlightingKind::Namespace);
return;
}
if (isa<NamespaceAliasDecl>(D)) {
addToken(Loc, HighlightingKind::Namespace);
return;
}
} }
void addToken(SourceLocation Loc, HighlightingKind Kind) { void addToken(SourceLocation Loc, HighlightingKind Kind) {
@ -218,6 +249,8 @@ llvm::StringRef toTextMateScope(HighlightingKind Kind) {
return "entity.name.type.class.cpp"; return "entity.name.type.class.cpp";
case HighlightingKind::Enum: case HighlightingKind::Enum:
return "entity.name.type.enum.cpp"; return "entity.name.type.enum.cpp";
case HighlightingKind::Namespace:
return "entity.name.namespace.cpp";
case HighlightingKind::NumKinds: case HighlightingKind::NumKinds:
llvm_unreachable("must not pass NumKinds to the function"); llvm_unreachable("must not pass NumKinds to the function");
} }

View File

@ -28,6 +28,7 @@ enum class HighlightingKind {
Function, Function,
Class, Class,
Enum, Enum,
Namespace,
NumKinds, NumKinds,
}; };

View File

@ -9,12 +9,15 @@
# CHECK-NEXT: ], # CHECK-NEXT: ],
# CHECK-NEXT: [ # CHECK-NEXT: [
# CHECK-NEXT: "entity.name.function.cpp" # CHECK-NEXT: "entity.name.function.cpp"
# CHECK-NEXT: ] # CHECK-NEXT: ],
# CHECK-NEXT: [ # CHECK-NEXT: [
# CHECK-NEXT: "entity.name.type.class.cpp" # CHECK-NEXT: "entity.name.type.class.cpp"
# CHECK-NEXT: ], # CHECK-NEXT: ],
# CHECK-NEXT: [ # CHECK-NEXT: [
# CHECK-NEXT: "entity.name.type.enum.cpp" # CHECK-NEXT: "entity.name.type.enum.cpp"
# CHECK-NEXT: ],
# CHECK-NEXT: [
# CHECK-NEXT: "entity.name.namespace.cpp"
# CHECK-NEXT: ] # CHECK-NEXT: ]
# CHECK-NEXT: ] # CHECK-NEXT: ]
# CHECK-NEXT: }, # CHECK-NEXT: },

View File

@ -36,7 +36,8 @@ void checkHighlightings(llvm::StringRef Code) {
{HighlightingKind::Variable, "Variable"}, {HighlightingKind::Variable, "Variable"},
{HighlightingKind::Function, "Function"}, {HighlightingKind::Function, "Function"},
{HighlightingKind::Class, "Class"}, {HighlightingKind::Class, "Class"},
{HighlightingKind::Enum, "Enum"}}; {HighlightingKind::Enum, "Enum"},
{HighlightingKind::Namespace, "Namespace"}};
std::vector<HighlightingToken> ExpectedTokens; std::vector<HighlightingToken> ExpectedTokens;
for (const auto &KindString : KindToString) { for (const auto &KindString : KindToString) {
std::vector<HighlightingToken> Toks = makeHighlightingTokens( std::vector<HighlightingToken> Toks = makeHighlightingTokens(
@ -75,18 +76,18 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
}; };
)cpp", )cpp",
R"cpp( R"cpp(
namespace abc { namespace $Namespace[[abc]] {
template<typename T> template<typename T>
struct $Class[[A]] { struct $Class[[A]] {
T t; T t;
}; };
} }
template<typename T> template<typename T>
struct $Class[[C]] : abc::A<T> { struct $Class[[C]] : $Namespace[[abc]]::A<T> {
typename T::A* D; typename T::A* D;
}; };
abc::$Class[[A]]<int> $Variable[[AA]]; $Namespace[[abc]]::$Class[[A]]<int> $Variable[[AA]];
typedef abc::$Class[[A]]<int> AAA; typedef $Namespace[[abc]]::$Class[[A]]<int> AAA;
struct $Class[[B]] { struct $Class[[B]] {
$Class[[B]](); $Class[[B]]();
~$Class[[B]](); ~$Class[[B]]();
@ -108,6 +109,29 @@ TEST(SemanticHighlighting, GetsCorrectTokens) {
$Enum[[E]] EEE; $Enum[[E]] EEE;
$Enum[[EE]] EEEE; $Enum[[EE]] EEEE;
}; };
)cpp",
R"cpp(
namespace $Namespace[[abc]] {
namespace {}
namespace $Namespace[[bcd]] {
struct $Class[[A]] {};
namespace $Namespace[[cde]] {
struct $Class[[A]] {
enum class $Enum[[B]] {
Hi,
};
};
}
}
}
using namespace $Namespace[[abc]]::$Namespace[[bcd]];
namespace $Namespace[[vwz]] =
$Namespace[[abc]]::$Namespace[[bcd]]::$Namespace[[cde]];
$Namespace[[abc]]::$Namespace[[bcd]]::$Class[[A]] $Variable[[AA]];
$Namespace[[vwz]]::$Class[[A]]::$Enum[[B]] $Variable[[AAA]] =
$Namespace[[vwz]]::$Class[[A]]::$Enum[[B]]::Hi;
::$Namespace[[vwz]]::$Class[[A]] $Variable[[B]];
::$Namespace[[abc]]::$Namespace[[bcd]]::$Class[[A]] $Variable[[BB]];
)cpp"}; )cpp"};
for (const auto &TestCase : TestCases) { for (const auto &TestCase : TestCases) {
checkHighlightings(TestCase); checkHighlightings(TestCase);