diff --git a/clang-tools-extra/clangd/SemanticHighlighting.h b/clang-tools-extra/clangd/SemanticHighlighting.h --- a/clang-tools-extra/clangd/SemanticHighlighting.h +++ b/clang-tools-extra/clangd/SemanticHighlighting.h @@ -67,6 +67,7 @@ Static, Abstract, DependentName, + DefaultLibrary, FunctionScope, ClassScope, diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -245,6 +245,16 @@ return false; } +/// 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); +} + // For a macro usage `DUMP(foo)`, we want: // - DUMP --> "macro" // - foo --> "variable". @@ -420,6 +430,8 @@ }; llvm::Optional scopeModifier(const NamedDecl *D) { + if (!D) + return llvm::None; const DeclContext *DC = D->getDeclContext(); // Injected "Foo" within the class "Foo" has file scope, not class scope. if (auto *R = dyn_cast_or_null(D)) @@ -456,6 +468,8 @@ return scopeModifier(TD->getDecl()); if (auto *TD = T->getAsTagDecl()) return scopeModifier(TD); + if (auto *OT = dyn_cast(T)) + return scopeModifier(OT->getInterface()); return llvm::None; } @@ -493,7 +507,7 @@ // We handle objective-C selectors specially, because one reference can // cover several non-contiguous tokens. void highlightObjCSelector(const ArrayRef &Locs, bool Decl, - bool Class) { + bool Class, bool DefaultLibrary) { HighlightingKind Kind = Class ? HighlightingKind::StaticMethod : HighlightingKind::Method; for (SourceLocation Part : Locs) { @@ -503,20 +517,27 @@ Tok.addModifier(HighlightingModifier::Declaration); if (Class) Tok.addModifier(HighlightingModifier::Static); + if (DefaultLibrary) + Tok.addModifier(HighlightingModifier::DefaultLibrary); } } bool VisitObjCMethodDecl(ObjCMethodDecl *OMD) { llvm::SmallVector Locs; OMD->getSelectorLocs(Locs); - highlightObjCSelector(Locs, /*Decl=*/true, OMD->isClassMethod()); + highlightObjCSelector(Locs, /*Decl=*/true, OMD->isClassMethod(), + isDefaultLibrary(OMD)); return true; } bool VisitObjCMessageExpr(ObjCMessageExpr *OME) { llvm::SmallVector Locs; OME->getSelectorLocs(Locs); - highlightObjCSelector(Locs, /*Decl=*/false, OME->isClassMessage()); + bool DefaultLibrary = false; + if (ObjCMethodDecl *OMD = OME->getMethodDecl()) + DefaultLibrary = isDefaultLibrary(OMD); + highlightObjCSelector(Locs, /*Decl=*/false, OME->isClassMessage(), + DefaultLibrary); return true; } @@ -642,6 +663,8 @@ Tok.addModifier(HighlightingModifier::Abstract); if (isDependent(Decl)) Tok.addModifier(HighlightingModifier::DependentName); + if (isDefaultLibrary(Decl)) + Tok.addModifier(HighlightingModifier::DefaultLibrary); if (Decl->isDeprecated()) Tok.addModifier(HighlightingModifier::Deprecated); // Do not treat an UnresolvedUsingValueDecl as a declaration. @@ -826,6 +849,8 @@ return "abstract"; case HighlightingModifier::DependentName: return "dependentName"; // nonstandard + case HighlightingModifier::DefaultLibrary: + return "defaultLibrary"; case HighlightingModifier::FunctionScope: return "functionScope"; // nonstandard case HighlightingModifier::ClassScope: diff --git a/clang-tools-extra/clangd/test/initialize-params.test b/clang-tools-extra/clangd/test/initialize-params.test --- a/clang-tools-extra/clangd/test/initialize-params.test +++ b/clang-tools-extra/clangd/test/initialize-params.test @@ -90,6 +90,7 @@ # CHECK-NEXT: "static", # CHECK-NEXT: "abstract", # CHECK-NEXT: "dependentName", +# CHECK-NEXT: "defaultLibrary", # CHECK-NEXT: "functionScope", # CHECK-NEXT: "classScope", # CHECK-NEXT: "fileScope", diff --git a/clang-tools-extra/clangd/test/semantic-tokens.test b/clang-tools-extra/clangd/test/semantic-tokens.test --- a/clang-tools-extra/clangd/test/semantic-tokens.test +++ b/clang-tools-extra/clangd/test/semantic-tokens.test @@ -23,7 +23,7 @@ # CHECK-NEXT: 4, # CHECK-NEXT: 1, # CHECK-NEXT: 0, -# CHECK-NEXT: 1025 +# CHECK-NEXT: 2049 # CHECK-NEXT: ], # CHECK-NEXT: "resultId": "1" # CHECK-NEXT: } @@ -49,7 +49,7 @@ # CHECK-NEXT: 4, # CHECK-NEXT: 1, # CHECK-NEXT: 0, -# CHECK-NEXT: 1025 +# CHECK-NEXT: 2049 # CHECK-NEXT: ], # Inserted at position 1 # CHECK-NEXT: "deleteCount": 0, @@ -72,12 +72,12 @@ # CHECK-NEXT: 4, # CHECK-NEXT: 1, # CHECK-NEXT: 0, -# CHECK-NEXT: 1025, +# CHECK-NEXT: 2049, # CHECK-NEXT: 1, # CHECK-NEXT: 4, # CHECK-NEXT: 1, # CHECK-NEXT: 0, -# CHECK-NEXT: 1025 +# CHECK-NEXT: 2049 # CHECK-NEXT: ], # CHECK-NEXT: "resultId": "3" # CHECK-NEXT: } diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp --- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp @@ -69,13 +69,16 @@ std::vector> AdditionalFiles = {}, - uint32_t ModifierMask = -1) { + uint32_t ModifierMask = -1, + std::vector AdditionalArgs = {}) { Annotations Test(Code); TestTU TU; TU.Code = std::string(Test.code()); TU.ExtraArgs.push_back("-std=c++20"); TU.ExtraArgs.push_back("-xobjective-c++"); + TU.ExtraArgs.insert(std::end(TU.ExtraArgs), std::begin(AdditionalArgs), + std::end(AdditionalArgs)); for (auto File : AdditionalFiles) TU.AdditionalFiles.insert({File.first, std::string(File.second)}); @@ -731,6 +734,24 @@ #define DEFINE_Y DEFINE(Y) )cpp"}}, ~ScopeModifierMask); + + checkHighlightings(R"cpp( + #include "SYSObject.h" + @interface $Class_defaultLibrary[[SYSObject]] ($Namespace_decl[[UserCategory]]) + @property(nonatomic, readonly) int $Field_decl_readonly[[user_property]]; + @end + int $Function_decl[[somethingUsingSystemSymbols]]() { + $Class_defaultLibrary[[SYSObject]] *$LocalVariable_decl[[obj]] = [$Class_defaultLibrary[[SYSObject]] $StaticMethod_static_defaultLibrary[[new]]]; + return $LocalVariable[[obj]].$Field_defaultLibrary[[value]] + $LocalVariable[[obj]].$Field_readonly[[user_property]]; + } + )cpp", + {{"SystemSDK/SYSObject.h", R"cpp( + @interface SYSObject + @property(nonatomic, assign) int value; + + (instancetype)new; + @end + )cpp"}}, + ~ScopeModifierMask, {"-isystemSystemSDK/"}); } TEST(SemanticHighlighting, ScopeModifiers) {