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 @@ -35,6 +35,7 @@ Namespace, TemplateParameter, Primitive, + LocalVariable, NumKinds, }; 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 @@ -225,7 +225,11 @@ addToken(Loc, HighlightingKind::Parameter); return; } - if (isa(D)) { + if (const VarDecl *VD = dyn_cast(D)) { + if (VD->isLocalVarDecl()) { + addToken(Loc, HighlightingKind::LocalVariable); + return; + } addToken(Loc, HighlightingKind::Variable); return; } @@ -256,7 +260,7 @@ } void addToken(SourceLocation Loc, HighlightingKind Kind) { - if(Loc.isMacroID()) { + if (Loc.isMacroID()) { // Only intereseted in highlighting arguments in macros (DEF_X(arg)). if (!SM.isMacroArgExpansion(Loc)) return; @@ -266,8 +270,8 @@ // Non top level decls that are included from a header are not filtered by // topLevelDecls. (example: method declarations being included from another // file for a class from another file) - // There are also cases with macros where the spelling loc will not be in the - // main file and the highlighting would be incorrect. + // There are also cases with macros where the spelling loc will not be in + // the main file and the highlighting would be incorrect. if (!isInsideMainFile(Loc, SM)) return; @@ -340,8 +344,10 @@ std::vector diffHighlightings(ArrayRef New, ArrayRef Old, int NewMaxLine) { - assert(std::is_sorted(New.begin(), New.end()) && "New must be a sorted vector"); - assert(std::is_sorted(Old.begin(), Old.end()) && "Old must be a sorted vector"); + assert(std::is_sorted(New.begin(), New.end()) && + "New must be a sorted vector"); + assert(std::is_sorted(Old.begin(), Old.end()) && + "Old must be a sorted vector"); // FIXME: There's an edge case when tokens span multiple lines. If the first // token on the line started on a line above the current one and the rest of @@ -365,9 +371,9 @@ auto OldEnd = Old.end(); auto NextLineNumber = [&]() { int NextNew = NewLine.end() != NewEnd ? NewLine.end()->R.start.line - : std::numeric_limits::max(); + : std::numeric_limits::max(); int NextOld = OldLine.end() != OldEnd ? OldLine.end()->R.start.line - : std::numeric_limits::max(); + : std::numeric_limits::max(); return std::min(NextNew, NextOld); }; @@ -452,6 +458,8 @@ return "entity.name.type.template.cpp"; case HighlightingKind::Primitive: return "storage.type.primitive.cpp"; + case HighlightingKind::LocalVariable: + return "variable.other.local.cpp"; case HighlightingKind::NumKinds: llvm_unreachable("must not pass NumKinds to the function"); } diff --git a/clang-tools-extra/clangd/test/semantic-highlighting.test b/clang-tools-extra/clangd/test/semantic-highlighting.test --- a/clang-tools-extra/clangd/test/semantic-highlighting.test +++ b/clang-tools-extra/clangd/test/semantic-highlighting.test @@ -36,6 +36,9 @@ # CHECK-NEXT: ], # CHECK-NEXT: [ # CHECK-NEXT: "storage.type.primitive.cpp" +# CHECK-NEXT: ], +# CHECK-NEXT: [ +# CHECK-NEXT: "variable.other.local.cpp" # CHECK-NEXT: ] # CHECK-NEXT: ] # 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 @@ -41,7 +41,8 @@ {HighlightingKind::Field, "Field"}, {HighlightingKind::Method, "Method"}, {HighlightingKind::TemplateParameter, "TemplateParameter"}, - {HighlightingKind::Primitive, "Primitive"}}; + {HighlightingKind::Primitive, "Primitive"}, + {HighlightingKind::LocalVariable, "LocalVariable"}}; std::vector ExpectedTokens; for (const auto &KindString : KindToString) { std::vector Toks = makeHighlightingTokens( @@ -99,31 +100,31 @@ TEST(SemanticHighlighting, GetsCorrectTokens) { const char *TestCases[] = { - R"cpp( + R"cpp( struct $Class[[AS]] { $Primitive[[double]] $Field[[SomeMember]]; }; struct { } $Variable[[S]]; $Primitive[[void]] $Function[[foo]]($Primitive[[int]] $Parameter[[A]], $Class[[AS]] $Parameter[[As]]) { - $Primitive[[auto]] $Variable[[VeryLongVariableName]] = 12312; - $Class[[AS]] $Variable[[AA]]; - $Primitive[[auto]] $Variable[[L]] = $Variable[[AA]].$Field[[SomeMember]] + $Parameter[[A]]; - auto $Variable[[FN]] = [ $Variable[[AA]]]($Primitive[[int]] $Parameter[[A]]) -> $Primitive[[void]] {}; - $Variable[[FN]](12312); + $Primitive[[auto]] $LocalVariable[[VeryLongVariableName]] = 12312; + $Class[[AS]] $LocalVariable[[AA]]; + $Primitive[[auto]] $LocalVariable[[L]] = $LocalVariable[[AA]].$Field[[SomeMember]] + $Parameter[[A]]; + auto $LocalVariable[[FN]] = [ $LocalVariable[[AA]]]($Primitive[[int]] $Parameter[[A]]) -> $Primitive[[void]] {}; + $LocalVariable[[FN]](12312); } )cpp", - R"cpp( + R"cpp( $Primitive[[void]] $Function[[foo]]($Primitive[[int]]); $Primitive[[void]] $Function[[Gah]](); $Primitive[[void]] $Function[[foo]]() { - auto $Variable[[Bou]] = $Function[[Gah]]; + auto $LocalVariable[[Bou]] = $Function[[Gah]]; } struct $Class[[A]] { $Primitive[[void]] $Method[[abc]](); }; )cpp", - R"cpp( + R"cpp( namespace $Namespace[[abc]] { template struct $Class[[A]] { @@ -145,12 +146,12 @@ $Class[[B]]::$Class[[B]]() {} $Class[[B]]::~$Class[[B]]() {} $Primitive[[void]] $Function[[f]] () { - $Class[[B]] $Variable[[BB]] = $Class[[B]](); - $Variable[[BB]].~$Class[[B]](); + $Class[[B]] $LocalVariable[[BB]] = $Class[[B]](); + $LocalVariable[[BB]].~$Class[[B]](); $Class[[B]](); } )cpp", - R"cpp( + R"cpp( enum class $Enum[[E]] { $EnumConstant[[A]], $EnumConstant[[B]], @@ -165,7 +166,7 @@ $Primitive[[int]] $Variable[[I]] = $EnumConstant[[Hi]]; $Enum[[E]] $Variable[[L]] = $Enum[[E]]::$EnumConstant[[B]]; )cpp", - R"cpp( + R"cpp( namespace $Namespace[[abc]] { namespace {} namespace $Namespace[[bcd]] { @@ -188,7 +189,7 @@ ::$Namespace[[vwz]]::$Class[[A]] $Variable[[B]]; ::$Namespace[[abc]]::$Namespace[[bcd]]::$Class[[A]] $Variable[[BB]]; )cpp", - R"cpp( + R"cpp( struct $Class[[D]] { $Primitive[[double]] $Field[[C]]; }; @@ -205,21 +206,21 @@ } }; $Primitive[[void]] $Function[[foo]]() { - $Class[[A]] $Variable[[AA]]; - $Variable[[AA]].$Field[[B]] += 2; - $Variable[[AA]].$Method[[foo]](); - $Variable[[AA]].$Field[[E]].$Field[[C]]; + $Class[[A]] $LocalVariable[[AA]]; + $LocalVariable[[AA]].$Field[[B]] += 2; + $LocalVariable[[AA]].$Method[[foo]](); + $LocalVariable[[AA]].$Field[[E]].$Field[[C]]; $Class[[A]]::$Variable[[S]] = 90; } )cpp", - R"cpp( + R"cpp( struct $Class[[AA]] { $Primitive[[int]] $Field[[A]]; } $Primitive[[int]] $Variable[[B]]; $Class[[AA]] $Variable[[A]]{$Variable[[B]]}; )cpp", - R"cpp( + R"cpp( namespace $Namespace[[a]] { struct $Class[[A]] {}; typedef $Primitive[[char]] $Primitive[[C]]; @@ -235,7 +236,7 @@ typedef $Namespace[[a]]::$Primitive[[C]] $Primitive[[PC]]; typedef $Primitive[[float]] $Primitive[[F]]; )cpp", - R"cpp( + R"cpp( template class $Class[[A]] { $TemplateParameter[[T]] $Field[[AA]]; @@ -261,16 +262,16 @@ template $Primitive[[void]] $Function[[foo]]($TemplateParameter[[T]] ...); )cpp", - R"cpp( + R"cpp( template struct $Class[[Tmpl]] {$TemplateParameter[[T]] $Field[[x]] = 0;}; extern template struct $Class[[Tmpl]]<$Primitive[[float]]>; template struct $Class[[Tmpl]]<$Primitive[[double]]>; )cpp", - // This test is to guard against highlightings disappearing when using - // conversion operators as their behaviour in the clang AST differ from - // other CXXMethodDecls. - R"cpp( + // This test is to guard against highlightings disappearing when using + // conversion operators as their behaviour in the clang AST differ from + // other CXXMethodDecls. + R"cpp( class $Class[[Foo]] {}; struct $Class[[Bar]] { explicit operator $Class[[Foo]]*() const; @@ -278,13 +279,13 @@ operator $Class[[Foo]](); }; $Primitive[[void]] $Function[[f]]() { - $Class[[Bar]] $Variable[[B]]; - $Class[[Foo]] $Variable[[F]] = $Variable[[B]]; - $Class[[Foo]] *$Variable[[FP]] = ($Class[[Foo]]*)$Variable[[B]]; - $Primitive[[int]] $Variable[[I]] = ($Primitive[[int]])$Variable[[B]]; + $Class[[Bar]] $LocalVariable[[B]]; + $Class[[Foo]] $LocalVariable[[F]] = $LocalVariable[[B]]; + $Class[[Foo]] *$LocalVariable[[FP]] = ($Class[[Foo]]*)$LocalVariable[[B]]; + $Primitive[[int]] $LocalVariable[[I]] = ($Primitive[[int]])$LocalVariable[[B]]; } )cpp" - R"cpp( + R"cpp( struct $Class[[B]] {}; struct $Class[[A]] { $Class[[B]] $Field[[BB]]; @@ -293,7 +294,7 @@ $Class[[A]] &$Class[[A]]::operator=($Class[[A]] &&$Parameter[[O]]) = default; )cpp", - R"cpp( + R"cpp( enum $Enum[[En]] { $EnumConstant[[EC]], }; @@ -311,7 +312,7 @@ $Class[[Bar2]]() : $Class[[Bar]]($Class[[Foo]](), $EnumConstant[[EC]]) {} }; )cpp", - R"cpp( + R"cpp( enum $Enum[[E]] { $EnumConstant[[E]], }; @@ -325,7 +326,7 @@ $Primitive[[decltype]]($Variable[[Form]]) $Variable[[F]] = 10; auto $Variable[[Fun]] = []()->$Primitive[[void]]{}; )cpp", - R"cpp( + R"cpp( class $Class[[G]] {}; template<$Class[[G]] *$TemplateParameter[[U]]> class $Class[[GP]] {}; @@ -340,19 +341,19 @@ template<$Primitive[[unsigned]] $TemplateParameter[[U]] = 2> class $Class[[Foo]] { $Primitive[[void]] $Method[[f]]() { - for($Primitive[[int]] $Variable[[I]] = 0; - $Variable[[I]] < $TemplateParameter[[U]];) {} + for($Primitive[[int]] $LocalVariable[[I]] = 0; + $LocalVariable[[I]] < $TemplateParameter[[U]];) {} } }; $Class[[G]] $Variable[[L]]; $Primitive[[void]] $Function[[f]]() { - $Class[[Foo]]<123> $Variable[[F]]; - $Class[[GP]]<&$Variable[[L]]> $Variable[[LL]]; - $Class[[GR]]<$Variable[[L]]> $Variable[[LLL]]; + $Class[[Foo]]<123> $LocalVariable[[F]]; + $Class[[GP]]<&$Variable[[L]]> $LocalVariable[[LL]]; + $Class[[GR]]<$Variable[[L]]> $LocalVariable[[LLL]]; } )cpp", - R"cpp( + R"cpp( template struct $Class[[G]] { @@ -372,14 +373,14 @@ }; $Primitive[[void]] $Function[[foo]]() { - $Class[[F]] $Variable[[FF]]; - $Class[[G]]<$Class[[F]], &$Class[[F]]::$Method[[f]]> $Variable[[GG]]; - $Variable[[GG]].$Method[[foo]](&$Variable[[FF]]); - $Class[[A]]<$Function[[foo]]> $Variable[[AA]]; + $Class[[F]] $LocalVariable[[FF]]; + $Class[[G]]<$Class[[F]], &$Class[[F]]::$Method[[f]]> $LocalVariable[[GG]]; + $LocalVariable[[GG]].$Method[[foo]](&$LocalVariable[[FF]]); + $Class[[A]]<$Function[[foo]]> $LocalVariable[[AA]]; )cpp", - // Tokens that share a source range but have conflicting Kinds are not - // highlighted. - R"cpp( + // Tokens that share a source range but have conflicting Kinds are not + // highlighted. + R"cpp( #define DEF_MULTIPLE(X) namespace X { class X { int X; }; } #define DEF_CLASS(T) class T {}; DEF_MULTIPLE(XYZ); @@ -395,17 +396,17 @@ #define SOME_NAME_SET variable2 = 123 #define INC_VAR(X) X += 2 $Primitive[[void]] $Function[[foo]]() { - DEF_VAR($Variable[[X]], 123); - DEF_VAR_REV(908, $Variable[[XY]]); - $Primitive[[int]] CPY( $Variable[[XX]] ); - DEF_VAR_TYPE($Class[[A]], $Variable[[AA]]); + DEF_VAR($LocalVariable[[X]], 123); + DEF_VAR_REV(908, $LocalVariable[[XY]]); + $Primitive[[int]] CPY( $LocalVariable[[XX]] ); + DEF_VAR_TYPE($Class[[A]], $LocalVariable[[AA]]); $Primitive[[double]] SOME_NAME; $Primitive[[int]] SOME_NAME_SET; - $Variable[[variable]] = 20.1; + $LocalVariable[[variable]] = 20.1; MACRO_CONCAT(var, 2, $Primitive[[float]]); - DEF_VAR_T($Class[[A]], CPY(CPY($Variable[[Nested]])), + DEF_VAR_T($Class[[A]], CPY(CPY($LocalVariable[[Nested]])), CPY($Class[[A]]())); - INC_VAR($Variable[[variable]]); + INC_VAR($LocalVariable[[variable]]); } $Primitive[[void]] SOME_NAME(); DEF_VAR($Variable[[XYZ]], 567); @@ -417,7 +418,7 @@ CALL_FN($Function[[foo]]); } )cpp", - R"cpp( + R"cpp( #define fail(expr) expr #define assert(COND) if (!(COND)) { fail("assertion failed" #COND); } $Primitive[[int]] $Variable[[x]];