[clangd] highlight import and export keywords for C++20 modules (#204511)

Add syntax highlighting for C++20 module `import` and `export` keywords.

Note: Highlighting of the `export` keyword in a module export statement is not possible, because such statements don't appear in the AST
This commit is contained in:
Access 2026-07-15 22:44:02 +09:00 committed by GitHub
parent a4d12bf0c2
commit 25682c3470
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 64 additions and 1 deletions

View file

@ -582,6 +582,18 @@ public:
return true;
}
bool VisitImportDecl(const ImportDecl *D) {
H.addToken(D->getLocation(), HighlightingKind::Modifier);
for (const auto ModuleLoc : D->getIdentifierLocs()) {
H.addToken(ModuleLoc, HighlightingKind::Namespace);
}
return true;
}
bool VisitExportDecl(const ExportDecl *D) {
H.addToken(D->getLocation(), HighlightingKind::Modifier);
return true;
}
bool VisitTagDecl(TagDecl *D) {
for (TemplateParameterList *TPL : D->getTemplateParameterLists())
H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc());

View file

@ -17,6 +17,7 @@
#include "ModulesBuilder.h"
#include "Preamble.h"
#include "ProjectModules.h"
#include "SemanticHighlighting.h"
#include "TestTU.h"
#include "support/Path.h"
#include "support/ThreadsafeFS.h"
@ -575,7 +576,8 @@ int use() { return a; }
ModulesBuilder Builder(CDB);
auto UseInfo = Builder.buildPrerequisiteModulesFor(getFullPath("Use.cpp"), FS);
auto UseInfo =
Builder.buildPrerequisiteModulesFor(getFullPath("Use.cpp"), FS);
ASSERT_TRUE(UseInfo);
HeaderSearchOptions HSOpts;
@ -1669,6 +1671,55 @@ void use() {}
getFullPath("Consumer.cpp"), *NewCI));
}
TEST_F(PrerequisiteModulesTests, ModuleSemanticHighlighting) {
MockDirectoryCompilationDatabase CDB(TestDir, FS);
llvm::StringRef AnnotatedCode = R"cpp(
module;
$import[[import]] M;
export module highlight;
$export[[export]] void foo() {
}
)cpp";
Annotations UseCpp(AnnotatedCode);
CDB.addFile("M.cppm", R"cpp(
export module M;
export struct TypeFromModule {};
)cpp");
CDB.addFile("Use.cpp", UseCpp.code());
ModulesBuilder Builder(CDB);
auto Inputs = getInputs("Use.cpp", CDB);
Inputs.ModulesManager = &Builder;
Inputs.Opts.SkipPreambleBuild = true;
auto CI = buildCompilerInvocation(Inputs, DiagConsumer);
ASSERT_TRUE(CI);
auto Preamble =
buildPreamble(getFullPath("Use.cpp"), *CI, Inputs, /*StoreInMemory=*/true,
/*PeambleCallback=*/nullptr);
ASSERT_TRUE(Preamble);
auto AST = ParsedAST::build(getFullPath("Use.cpp"), Inputs, std::move(CI), {},
Preamble);
ASSERT_TRUE(AST);
auto Actual = getSemanticHighlightings(AST.value(),
/*IncludeInactiveRegionTokens=*/true);
auto HasToken = [&](llvm::StringRef Name, HighlightingKind Kind) {
return llvm::any_of(Actual, [&](const HighlightingToken &T) {
return T.Kind == Kind && T.R == UseCpp.range(Name);
});
};
EXPECT_TRUE(HasToken("import", HighlightingKind::Modifier));
EXPECT_TRUE(HasToken("export", HighlightingKind::Modifier));
}
} // namespace
} // namespace clang::clangd