-
Notifications
You must be signed in to change notification settings - Fork 12.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[clangd] Added functionality for getting semantic highlights for vari…
…able and function declarations llvm-svn: 364421
- Loading branch information
Showing
5 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| //===--- SemanticHighlighting.cpp - -------------------------- ---*- C++ -*-===// | ||
| // | ||
| // 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" | ||
| #include "Logger.h" | ||
| #include "SourceCode.h" | ||
| #include "clang/AST/ASTContext.h" | ||
| #include "clang/AST/RecursiveASTVisitor.h" | ||
|
|
||
| namespace clang { | ||
| namespace clangd { | ||
| namespace { | ||
|
|
||
| // Collects all semantic tokens in an ASTContext. | ||
| class HighlightingTokenCollector | ||
| : public RecursiveASTVisitor<HighlightingTokenCollector> { | ||
| std::vector<HighlightingToken> Tokens; | ||
| ASTContext &Ctx; | ||
| const SourceManager &SM; | ||
|
|
||
| public: | ||
| HighlightingTokenCollector(ParsedAST &AST) | ||
| : Ctx(AST.getASTContext()), SM(AST.getSourceManager()) {} | ||
|
|
||
| std::vector<HighlightingToken> collectTokens() { | ||
| Tokens.clear(); | ||
| TraverseAST(Ctx); | ||
| return Tokens; | ||
| } | ||
|
|
||
| bool VisitVarDecl(VarDecl *Var) { | ||
| addToken(Var, HighlightingKind::Variable); | ||
| return true; | ||
| } | ||
| bool VisitFunctionDecl(FunctionDecl *Func) { | ||
| addToken(Func, HighlightingKind::Function); | ||
| return true; | ||
| } | ||
|
|
||
| private: | ||
| void addToken(const NamedDecl *D, HighlightingKind Kind) { | ||
| if (D->getLocation().isMacroID()) | ||
| // FIXME: skip tokens inside macros for now. | ||
| return; | ||
|
|
||
| if (D->getDeclName().isEmpty()) | ||
| // Don't add symbols that don't have any length. | ||
| return; | ||
|
|
||
| auto R = getTokenRange(SM, Ctx.getLangOpts(), D->getLocation()); | ||
| if (!R) { | ||
| // R should always have a value, if it doesn't something is very wrong. | ||
| elog("Tried to add semantic token with an invalid range"); | ||
| return; | ||
| } | ||
|
|
||
| Tokens.push_back({Kind, R.getValue()}); | ||
| } | ||
| }; | ||
|
|
||
| } // namespace | ||
|
|
||
| bool operator==(const HighlightingToken &Lhs, const HighlightingToken &Rhs) { | ||
| return Lhs.Kind == Rhs.Kind && Lhs.R == Rhs.R; | ||
| } | ||
|
|
||
| std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST) { | ||
| AST.getASTContext().setTraversalScope(AST.getLocalTopLevelDecls()); | ||
| return HighlightingTokenCollector(AST).collectTokens(); | ||
| } | ||
|
|
||
| } // namespace clangd | ||
| } // namespace clang |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| //==-- SemanticHighlighting.h - Generating highlights from the AST-- C++ -*-==// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICHIGHLIGHT_H | ||
| #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SEMANTICHIGHLIGHT_H | ||
|
|
||
| #include "ClangdUnit.h" | ||
|
|
||
| namespace clang { | ||
| namespace clangd { | ||
|
|
||
| enum class HighlightingKind { | ||
| Variable, | ||
| Function, | ||
| }; | ||
|
|
||
| // Contains all information needed for the highlighting a token. | ||
| struct HighlightingToken { | ||
| HighlightingKind Kind; | ||
| Range R; | ||
| }; | ||
|
|
||
| bool operator==(const HighlightingToken &Lhs, const HighlightingToken &Rhs); | ||
|
|
||
| // Returns all HighlightingTokens from an AST. Only generates highlights for the | ||
| // main AST. | ||
| std::vector<HighlightingToken> getSemanticHighlightings(ParsedAST &AST); | ||
|
|
||
| } // namespace clangd | ||
| } // namespace clang | ||
|
|
||
| #endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| //==- SemanticHighlightingTests.cpp - SemanticHighlighting tests-*- C++ -* -==// | ||
| // | ||
| // 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 "Annotations.h" | ||
| #include "SemanticHighlighting.h" | ||
| #include "TestTU.h" | ||
| #include "gmock/gmock.h" | ||
|
|
||
| namespace clang { | ||
| namespace clangd { | ||
| namespace { | ||
|
|
||
| std::vector<HighlightingToken> | ||
| makeHighlightingTokens(llvm::ArrayRef<Range> Ranges, HighlightingKind Kind) { | ||
| std::vector<HighlightingToken> Tokens(Ranges.size()); | ||
| for (int I = 0, End = Ranges.size(); I < End; ++I) { | ||
| Tokens[I].R = Ranges[I]; | ||
| Tokens[I].Kind = Kind; | ||
| } | ||
|
|
||
| return Tokens; | ||
| } | ||
|
|
||
| void checkHighlightings(llvm::StringRef Code) { | ||
| Annotations Test(Code); | ||
| auto AST = TestTU::withCode(Test.code()).build(); | ||
| static const std::map<HighlightingKind, std::string> KindToString{ | ||
| {HighlightingKind::Variable, "Variable"}, | ||
| {HighlightingKind::Function, "Function"}}; | ||
| std::vector<HighlightingToken> ExpectedTokens; | ||
| for (const auto &KindString : KindToString) { | ||
| std::vector<HighlightingToken> Toks = | ||
| makeHighlightingTokens(Test.ranges(KindString.second), KindString.first); | ||
| ExpectedTokens.insert(ExpectedTokens.end(), Toks.begin(), Toks.end()); | ||
| } | ||
|
|
||
| auto ActualTokens = getSemanticHighlightings(AST); | ||
| EXPECT_THAT(ActualTokens, testing::UnorderedElementsAreArray(ExpectedTokens)); | ||
| } | ||
|
|
||
| TEST(SemanticHighlighting, GetsCorrectTokens) { | ||
| const char *TestCases[] = { | ||
| R"cpp( | ||
| struct A { | ||
| double SomeMember; | ||
| }; | ||
| struct { | ||
| } $Variable[[HStruct]]; | ||
| void $Function[[foo]](int $Variable[[a]]) { | ||
| auto $Variable[[VeryLongVariableName]] = 12312; | ||
| A $Variable[[aa]]; | ||
| } | ||
| )cpp", | ||
| R"cpp( | ||
| void $Function[[foo]](int); | ||
| )cpp"}; | ||
| for (const auto &TestCase : TestCases) { | ||
| checkHighlightings(TestCase); | ||
| } | ||
| } | ||
|
|
||
| } // namespace | ||
| } // namespace clangd | ||
| } // namespace clang |