forked from OSchip/llvm-project
[clangd] Add "Deprecated" field to Symbol and CodeCompletion.
Summary: Also set "deprecated" field in LSP CompletionItem. Reviewers: sammccall, kadircet Reviewed By: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits Differential Revision: https://reviews.llvm.org/D51724 llvm-svn: 341576
This commit is contained in:
parent
9e5c163154
commit
6df66001ee
|
@ -353,6 +353,8 @@ struct CodeCompletionBuilder {
|
|||
return std::tie(X.range.start.line, X.range.start.character) <
|
||||
std::tie(Y.range.start.line, Y.range.start.character);
|
||||
});
|
||||
Completion.Deprecated |=
|
||||
(C.SemaResult->Availability == CXAvailability_Deprecated);
|
||||
}
|
||||
if (C.IndexResult) {
|
||||
Completion.Origin |= C.IndexResult->Origin;
|
||||
|
@ -362,6 +364,7 @@ struct CodeCompletionBuilder {
|
|||
Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind);
|
||||
if (Completion.Name.empty())
|
||||
Completion.Name = C.IndexResult->Name;
|
||||
Completion.Deprecated |= (C.IndexResult->Flags & Symbol::Deprecated);
|
||||
}
|
||||
|
||||
// Turn absolute path into a literal string that can be #included.
|
||||
|
@ -1625,6 +1628,7 @@ CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const {
|
|||
LSP.kind = Kind;
|
||||
LSP.detail = BundleSize > 1 ? llvm::formatv("[{0} overloads]", BundleSize)
|
||||
: ReturnType;
|
||||
LSP.deprecated = Deprecated;
|
||||
if (InsertInclude)
|
||||
LSP.detail += "\n" + InsertInclude->Header;
|
||||
LSP.documentation = Documentation;
|
||||
|
@ -1656,6 +1660,7 @@ CompletionItem CodeCompletion::render(const CodeCompleteOptions &Opts) const {
|
|||
: InsertTextFormat::PlainText;
|
||||
if (InsertInclude && InsertInclude->Insertion)
|
||||
LSP.additionalTextEdits.push_back(*InsertInclude->Insertion);
|
||||
|
||||
return LSP;
|
||||
}
|
||||
|
||||
|
|
|
@ -177,6 +177,9 @@ struct CodeCompletion {
|
|||
};
|
||||
Scores Score;
|
||||
|
||||
/// Indicates if this item is deprecated.
|
||||
bool Deprecated = false;
|
||||
|
||||
// Serialize this to an LSP completion item. This is a lossy operation.
|
||||
CompletionItem render(const CodeCompleteOptions &) const;
|
||||
};
|
||||
|
|
|
@ -517,6 +517,8 @@ json::Value toJSON(const CompletionItem &CI) {
|
|||
Result["textEdit"] = *CI.textEdit;
|
||||
if (!CI.additionalTextEdits.empty())
|
||||
Result["additionalTextEdits"] = json::Array(CI.additionalTextEdits);
|
||||
if (CI.deprecated)
|
||||
Result["deprecated"] = CI.deprecated;
|
||||
return std::move(Result);
|
||||
}
|
||||
|
||||
|
|
|
@ -768,6 +768,9 @@ struct CompletionItem {
|
|||
/// themselves.
|
||||
std::vector<TextEdit> additionalTextEdits;
|
||||
|
||||
/// Indicates if this item is deprecated.
|
||||
bool deprecated = false;
|
||||
|
||||
// TODO(krasimir): The following optional fields defined by the language
|
||||
// server protocol are unsupported:
|
||||
//
|
||||
|
|
|
@ -167,9 +167,7 @@ static bool isInstanceMember(const index::SymbolInfo &D) {
|
|||
}
|
||||
|
||||
void SymbolQualitySignals::merge(const CodeCompletionResult &SemaCCResult) {
|
||||
if (SemaCCResult.Availability == CXAvailability_Deprecated)
|
||||
Deprecated = true;
|
||||
|
||||
Deprecated |= (SemaCCResult.Availability == CXAvailability_Deprecated);
|
||||
Category = categorize(SemaCCResult);
|
||||
|
||||
if (SemaCCResult.Declaration) {
|
||||
|
@ -180,6 +178,7 @@ void SymbolQualitySignals::merge(const CodeCompletionResult &SemaCCResult) {
|
|||
}
|
||||
|
||||
void SymbolQualitySignals::merge(const Symbol &IndexResult) {
|
||||
Deprecated |= (IndexResult.Flags & Symbol::Deprecated);
|
||||
References = std::max(IndexResult.References, References);
|
||||
Category = categorize(IndexResult.SymInfo);
|
||||
ReservedName = ReservedName || isReserved(IndexResult.Name);
|
||||
|
|
|
@ -55,6 +55,17 @@ raw_ostream &operator<<(raw_ostream &OS, SymbolOrigin O) {
|
|||
return OS;
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, Symbol::SymbolFlag F) {
|
||||
if (F == Symbol::None)
|
||||
return OS << "None";
|
||||
std::string s;
|
||||
if (F & Symbol::Deprecated)
|
||||
s += "deprecated|";
|
||||
if (F & Symbol::IndexedForCodeCompletion)
|
||||
s += "completion|";
|
||||
return OS << StringRef(s).rtrim('|');
|
||||
}
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const Symbol &S) {
|
||||
return OS << S.Scope << S.Name;
|
||||
}
|
||||
|
|
|
@ -201,9 +201,6 @@ struct Symbol {
|
|||
// The number of translation units that reference this symbol from their main
|
||||
// file. This number is only meaningful if aggregated in an index.
|
||||
unsigned References = 0;
|
||||
/// Whether or not this symbol is meant to be used for the code completion.
|
||||
/// See also isIndexedForCodeCompletion().
|
||||
bool IsIndexedForCodeCompletion = false;
|
||||
/// Where this symbol came from. Usually an index provides a constant value.
|
||||
SymbolOrigin Origin = SymbolOrigin::Unknown;
|
||||
/// A brief description of the symbol that can be appended in the completion
|
||||
|
@ -244,9 +241,27 @@ struct Symbol {
|
|||
/// any definition.
|
||||
llvm::SmallVector<IncludeHeaderWithReferences, 1> IncludeHeaders;
|
||||
|
||||
// FIXME: add extra fields for index scoring signals.
|
||||
enum SymbolFlag : uint8_t {
|
||||
None = 0,
|
||||
/// Whether or not this symbol is meant to be used for the code completion.
|
||||
/// See also isIndexedForCodeCompletion().
|
||||
IndexedForCodeCompletion = 1 << 0,
|
||||
/// Indicates if the symbol is deprecated.
|
||||
Deprecated = 1 << 1,
|
||||
};
|
||||
|
||||
SymbolFlag Flags = SymbolFlag::None;
|
||||
/// FIXME: also add deprecation message and fixit?
|
||||
};
|
||||
inline Symbol::SymbolFlag operator|(Symbol::SymbolFlag A, Symbol::SymbolFlag B) {
|
||||
return static_cast<Symbol::SymbolFlag>(static_cast<uint8_t>(A) |
|
||||
static_cast<uint8_t>(B));
|
||||
}
|
||||
inline Symbol::SymbolFlag &operator|=(Symbol::SymbolFlag &A, Symbol::SymbolFlag B) {
|
||||
return A = A | B;
|
||||
}
|
||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Symbol &S);
|
||||
raw_ostream &operator<<(raw_ostream &, Symbol::SymbolFlag);
|
||||
|
||||
// Invokes Callback with each StringRef& contained in the Symbol.
|
||||
// Useful for deduplicating backing strings.
|
||||
|
|
|
@ -35,7 +35,8 @@ bool MemIndex::fuzzyFind(
|
|||
// Exact match against all possible scopes.
|
||||
if (!Req.Scopes.empty() && !llvm::is_contained(Req.Scopes, Sym->Scope))
|
||||
continue;
|
||||
if (Req.RestrictForCodeCompletion && !Sym->IsIndexedForCodeCompletion)
|
||||
if (Req.RestrictForCodeCompletion &&
|
||||
!(Sym->Flags & Symbol::IndexedForCodeCompletion))
|
||||
continue;
|
||||
|
||||
if (auto Score = Filter.match(Sym->Name))
|
||||
|
|
|
@ -150,6 +150,7 @@ Symbol mergeSymbol(const Symbol &L, const Symbol &R) {
|
|||
}
|
||||
|
||||
S.Origin |= O.Origin | SymbolOrigin::Merge;
|
||||
S.Flags |= O.Flags;
|
||||
return S;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
#include "Serialization.h"
|
||||
#include "../RIFF.h"
|
||||
#include "Index.h"
|
||||
#include "llvm/Support/Compression.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
@ -200,7 +201,7 @@ void writeSymbol(const Symbol &Sym, const StringTableOut &Strings,
|
|||
}
|
||||
}
|
||||
writeVar(Sym.References, OS);
|
||||
OS.write(Sym.IsIndexedForCodeCompletion);
|
||||
OS.write(static_cast<uint8_t>(Sym.Flags));
|
||||
OS.write(static_cast<uint8_t>(Sym.Origin));
|
||||
writeVar(Strings.index(Sym.Signature), OS);
|
||||
writeVar(Strings.index(Sym.CompletionSnippetSuffix), OS);
|
||||
|
@ -274,7 +275,7 @@ Expected<Symbol> readSymbol(StringRef &Data, const StringTableIn &Strings) {
|
|||
}
|
||||
}
|
||||
Sym.References = consumeVar(Data);
|
||||
Sym.IsIndexedForCodeCompletion = consume8(Data);
|
||||
Sym.Flags = static_cast<Symbol::SymbolFlag>(consume8(Data));
|
||||
Sym.Origin = static_cast<SymbolOrigin>(consume8(Data));
|
||||
READ_STRING(Sym.Signature);
|
||||
READ_STRING(Sym.CompletionSnippetSuffix);
|
||||
|
@ -305,7 +306,7 @@ Expected<Symbol> readSymbol(StringRef &Data, const StringTableIn &Strings) {
|
|||
// The current versioning scheme is simple - non-current versions are rejected.
|
||||
// If you make a breaking change, bump this version number to invalidate stored
|
||||
// data. Later we may want to support some backward compatibility.
|
||||
constexpr static uint32_t Version = 2;
|
||||
constexpr static uint32_t Version = 3;
|
||||
|
||||
Expected<IndexFileIn> readIndexFile(StringRef Data) {
|
||||
auto RIFF = riff::readFile(Data);
|
||||
|
|
|
@ -396,7 +396,7 @@ bool SymbolCollector::handleMacroOccurence(const IdentifierInfo *Name,
|
|||
Symbol S;
|
||||
S.ID = std::move(*ID);
|
||||
S.Name = Name->getName();
|
||||
S.IsIndexedForCodeCompletion = true;
|
||||
S.Flags |= Symbol::IndexedForCodeCompletion;
|
||||
S.SymInfo = index::getSymbolInfoForMacro(*MI);
|
||||
std::string FileURI;
|
||||
if (auto DeclLoc = getTokenLocation(MI->getDefinitionLoc(), SM, Opts,
|
||||
|
@ -491,7 +491,8 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND,
|
|||
// FIXME: this returns foo:bar: for objective-C methods, we prefer only foo:
|
||||
// for consistency with CodeCompletionString and a clean name/signature split.
|
||||
|
||||
S.IsIndexedForCodeCompletion = isIndexedForCodeCompletion(ND, Ctx);
|
||||
if (isIndexedForCodeCompletion(ND, Ctx))
|
||||
S.Flags |= Symbol::IndexedForCodeCompletion;
|
||||
S.SymInfo = index::getSymbolInfo(&ND);
|
||||
std::string FileURI;
|
||||
if (auto DeclLoc = getTokenLocation(findNameLoc(&ND), SM, Opts,
|
||||
|
@ -531,6 +532,8 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND,
|
|||
S.IncludeHeaders.emplace_back(Include, 1);
|
||||
|
||||
S.Origin = Opts.Origin;
|
||||
if (ND.getAvailability() == AR_Deprecated)
|
||||
S.Flags |= Symbol::Deprecated;
|
||||
Symbols.insert(S);
|
||||
return Symbols.find(S.ID);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdint>
|
||||
|
||||
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(clang::clangd::Symbol)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences)
|
||||
|
@ -48,6 +49,19 @@ struct NormalizedSymbolID {
|
|||
std::string HexString;
|
||||
};
|
||||
|
||||
struct NormalizedSymbolFlag {
|
||||
NormalizedSymbolFlag(IO &) {}
|
||||
NormalizedSymbolFlag(IO &, Symbol::SymbolFlag F) {
|
||||
Flag = static_cast<uint8_t>(F);
|
||||
}
|
||||
|
||||
Symbol::SymbolFlag denormalize(IO &) {
|
||||
return static_cast<Symbol::SymbolFlag>(Flag);
|
||||
}
|
||||
|
||||
uint8_t Flag = 0;
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<SymbolLocation::Position> {
|
||||
static void mapping(IO &IO, SymbolLocation::Position &Value) {
|
||||
IO.mapRequired("Line", Value.Line);
|
||||
|
@ -83,6 +97,8 @@ struct MappingTraits<clang::clangd::Symbol::IncludeHeaderWithReferences> {
|
|||
template <> struct MappingTraits<Symbol> {
|
||||
static void mapping(IO &IO, Symbol &Sym) {
|
||||
MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID);
|
||||
MappingNormalization<NormalizedSymbolFlag, Symbol::SymbolFlag> NSymbolFlag(
|
||||
IO, Sym.Flags);
|
||||
IO.mapRequired("ID", NSymbolID->HexString);
|
||||
IO.mapRequired("Name", Sym.Name);
|
||||
IO.mapRequired("Scope", Sym.Scope);
|
||||
|
@ -91,8 +107,7 @@ template <> struct MappingTraits<Symbol> {
|
|||
SymbolLocation());
|
||||
IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
|
||||
IO.mapOptional("References", Sym.References, 0u);
|
||||
IO.mapOptional("IsIndexedForCodeCompletion", Sym.IsIndexedForCodeCompletion,
|
||||
false);
|
||||
IO.mapOptional("Flags", NSymbolFlag->Flag);
|
||||
IO.mapOptional("Signature", Sym.Signature);
|
||||
IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix);
|
||||
IO.mapOptional("Documentation", Sym.Documentation);
|
||||
|
|
|
@ -77,6 +77,7 @@ Matcher<const std::vector<CodeCompletion> &> Has(std::string Name,
|
|||
return Contains(AllOf(Named(std::move(Name)), Kind(K)));
|
||||
}
|
||||
MATCHER(IsDocumented, "") { return !arg.Documentation.empty(); }
|
||||
MATCHER(Deprecated, "") { return arg.Deprecated; }
|
||||
|
||||
std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
|
||||
SymbolSlab::Builder Slab;
|
||||
|
@ -161,7 +162,7 @@ Symbol sym(StringRef QName, index::SymbolKind Kind, StringRef USRFormat) {
|
|||
USR += Regex("^.*$").sub(USRFormat, Sym.Name); // e.g. func -> @F@func#
|
||||
Sym.ID = SymbolID(USR);
|
||||
Sym.SymInfo.Kind = Kind;
|
||||
Sym.IsIndexedForCodeCompletion = true;
|
||||
Sym.Flags |= Symbol::IndexedForCodeCompletion;
|
||||
Sym.Origin = SymbolOrigin::Static;
|
||||
return Sym;
|
||||
}
|
||||
|
@ -720,9 +721,11 @@ TEST(CompletionTest, Documentation) {
|
|||
TEST(CompletionTest, GlobalCompletionFiltering) {
|
||||
|
||||
Symbol Class = cls("XYZ");
|
||||
Class.IsIndexedForCodeCompletion = false;
|
||||
Class.Flags = static_cast<Symbol::SymbolFlag>(
|
||||
Class.Flags & ~(Symbol::IndexedForCodeCompletion));
|
||||
Symbol Func = func("XYZ::foooo");
|
||||
Func.IsIndexedForCodeCompletion = false;
|
||||
Func.Flags = static_cast<Symbol::SymbolFlag>(
|
||||
Func.Flags & ~(Symbol::IndexedForCodeCompletion));
|
||||
|
||||
auto Results = completions(R"(// void f() {
|
||||
XYZ::foooo^
|
||||
|
@ -1374,6 +1377,7 @@ TEST(CompletionTest, Render) {
|
|||
EXPECT_EQ(R.documentation, "This is x().");
|
||||
EXPECT_THAT(R.additionalTextEdits, IsEmpty());
|
||||
EXPECT_EQ(R.sortText, sortText(1.0, "x"));
|
||||
EXPECT_FALSE(R.deprecated);
|
||||
|
||||
Opts.EnableSnippets = true;
|
||||
R = C.render(Opts);
|
||||
|
@ -1392,6 +1396,10 @@ TEST(CompletionTest, Render) {
|
|||
C.BundleSize = 2;
|
||||
R = C.render(Opts);
|
||||
EXPECT_EQ(R.detail, "[2 overloads]\n\"foo.h\"");
|
||||
|
||||
C.Deprecated = true;
|
||||
R = C.render(Opts);
|
||||
EXPECT_TRUE(R.deprecated);
|
||||
}
|
||||
|
||||
TEST(CompletionTest, IgnoreRecoveryResults) {
|
||||
|
@ -1891,12 +1899,24 @@ TEST(CompletionTest, MergeMacrosFromIndexAndSema) {
|
|||
Sym.Name = "Clangd_Macro_Test";
|
||||
Sym.ID = SymbolID("c:foo.cpp@8@macro@Clangd_Macro_Test");
|
||||
Sym.SymInfo.Kind = index::SymbolKind::Macro;
|
||||
Sym.IsIndexedForCodeCompletion = true;
|
||||
Sym.Flags |= Symbol::IndexedForCodeCompletion;
|
||||
EXPECT_THAT(completions("#define Clangd_Macro_Test\nClangd_Macro_T^", {Sym})
|
||||
.Completions,
|
||||
UnorderedElementsAre(Named("Clangd_Macro_Test")));
|
||||
}
|
||||
|
||||
TEST(CompletionTest, DeprecatedResults) {
|
||||
std::string Body = R"cpp(
|
||||
void TestClangd();
|
||||
void TestClangc() __attribute__((deprecated("", "")));
|
||||
)cpp";
|
||||
|
||||
EXPECT_THAT(
|
||||
completions(Body + "int main() { TestClang^ }").Completions,
|
||||
UnorderedElementsAre(AllOf(Named("TestClangd"), Not(Deprecated())),
|
||||
AllOf(Named("TestClangc"), Deprecated())));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
|
|
@ -59,7 +59,7 @@ TEST(QualityTests, SymbolQualitySignalExtraction) {
|
|||
F.References = 24; // TestTU doesn't count references, so fake it.
|
||||
Quality = {};
|
||||
Quality.merge(F);
|
||||
EXPECT_FALSE(Quality.Deprecated); // FIXME: Include deprecated bit in index.
|
||||
EXPECT_TRUE(Quality.Deprecated);
|
||||
EXPECT_FALSE(Quality.ReservedName);
|
||||
EXPECT_EQ(Quality.References, 24u);
|
||||
EXPECT_EQ(Quality.Category, SymbolQualitySignals::Function);
|
||||
|
|
|
@ -35,7 +35,7 @@ CanonicalDeclaration:
|
|||
End:
|
||||
Line: 1
|
||||
Column: 1
|
||||
IsIndexedForCodeCompletion: true
|
||||
Flags: 1
|
||||
Documentation: 'Foo doc'
|
||||
ReturnType: 'int'
|
||||
IncludeHeaders:
|
||||
|
@ -62,7 +62,7 @@ CanonicalDeclaration:
|
|||
End:
|
||||
Line: 1
|
||||
Column: 1
|
||||
IsIndexedForCodeCompletion: false
|
||||
Flags: 2
|
||||
Signature: '-sig'
|
||||
CompletionSnippetSuffix: '-snippet'
|
||||
...
|
||||
|
@ -82,7 +82,8 @@ TEST(SerializationTest, YAMLConversions) {
|
|||
EXPECT_EQ(Sym1.Documentation, "Foo doc");
|
||||
EXPECT_EQ(Sym1.ReturnType, "int");
|
||||
EXPECT_EQ(Sym1.CanonicalDeclaration.FileURI, "file:///path/foo.h");
|
||||
EXPECT_TRUE(Sym1.IsIndexedForCodeCompletion);
|
||||
EXPECT_TRUE(Sym1.Flags & Symbol::IndexedForCodeCompletion);
|
||||
EXPECT_FALSE(Sym1.Flags & Symbol::Deprecated);
|
||||
EXPECT_THAT(Sym1.IncludeHeaders,
|
||||
UnorderedElementsAre(IncludeHeaderWithRef("include1", 7u),
|
||||
IncludeHeaderWithRef("include2", 3u)));
|
||||
|
@ -94,7 +95,8 @@ TEST(SerializationTest, YAMLConversions) {
|
|||
EXPECT_EQ(Sym2.Signature, "-sig");
|
||||
EXPECT_EQ(Sym2.ReturnType, "");
|
||||
EXPECT_EQ(Sym2.CanonicalDeclaration.FileURI, "file:///path/bar.h");
|
||||
EXPECT_FALSE(Sym2.IsIndexedForCodeCompletion);
|
||||
EXPECT_FALSE(Sym2.Flags & Symbol::IndexedForCodeCompletion);
|
||||
EXPECT_TRUE(Sym2.Flags & Symbol::Deprecated);
|
||||
|
||||
std::string ConcatenatedYAML;
|
||||
{
|
||||
|
|
|
@ -80,8 +80,10 @@ MATCHER_P(DefRange, Pos, "") {
|
|||
}
|
||||
MATCHER_P(RefCount, R, "") { return int(arg.References) == R; }
|
||||
MATCHER_P(ForCodeCompletion, IsIndexedForCodeCompletion, "") {
|
||||
return arg.IsIndexedForCodeCompletion == IsIndexedForCodeCompletion;
|
||||
return static_cast<bool>(arg.Flags & Symbol::IndexedForCodeCompletion) ==
|
||||
IsIndexedForCodeCompletion;
|
||||
}
|
||||
MATCHER(Deprecated, "") { return arg.Flags & Symbol::Deprecated; }
|
||||
MATCHER(RefRange, "") {
|
||||
const Ref &Pos = testing::get<0>(arg);
|
||||
const Range &Range = testing::get<1>(arg);
|
||||
|
@ -1014,6 +1016,17 @@ TEST_F(SymbolCollectorTest, CollectMacros) {
|
|||
DeclRange(Header.range("used")))));
|
||||
}
|
||||
|
||||
TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
|
||||
const std::string Header = R"(
|
||||
void TestClangc() __attribute__((deprecated("", "")));
|
||||
void TestClangd();
|
||||
)";
|
||||
runSymbolCollector(Header, /**/ "");
|
||||
EXPECT_THAT(Symbols, UnorderedElementsAre(
|
||||
AllOf(QName("TestClangc"), Deprecated()),
|
||||
AllOf(QName("TestClangd"), Not(Deprecated()))));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
|
Loading…
Reference in New Issue