usaxena95 updated this revision to Diff 280406. usaxena95 added a comment. Addressed offline comments.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D83814/new/ https://reviews.llvm.org/D83814 Files: clang-tools-extra/clangd/CMakeLists.txt clang-tools-extra/clangd/CompletionModel.cmake clang-tools-extra/clangd/CompletionModelCodegen.py clang-tools-extra/clangd/for-review-only/CompletionModel.cpp clang-tools-extra/clangd/for-review-only/CompletionModel.h clang-tools-extra/clangd/for-review-only/DecisionForestRuntimeTest.cpp clang-tools-extra/clangd/for-review-only/DecisionForestRuntimeTest.h clang-tools-extra/clangd/model/features.json clang-tools-extra/clangd/model/forest.json clang-tools-extra/clangd/unittests/CMakeLists.txt clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp clang-tools-extra/clangd/unittests/DecisionForestTests.cpp clang-tools-extra/clangd/unittests/model/CategoricalFeature.h clang-tools-extra/clangd/unittests/model/features.json clang-tools-extra/clangd/unittests/model/forest.json
Index: clang-tools-extra/clangd/unittests/model/forest.json =================================================================== --- /dev/null +++ clang-tools-extra/clangd/unittests/model/forest.json @@ -0,0 +1,52 @@ +[ + { + "operation": "if_greater", + "feature": "ANumber", + "threshold": 200.0, + "then": { + "operation": "if_greater", + "feature": "AFloat", + "threshold": -1, + "then": { + "operation": "boost", + "score": 10.0 + }, + "else": { + "operation": "boost", + "score": -20.0 + } + }, + "else": { + "operation": "if_member", + "feature": "ACategorical", + "set": [ + "A", + "C" + ], + "then": { + "operation": "boost", + "score": 3.0 + }, + "else": { + "operation": "boost", + "score": -4.0 + } + } + }, + { + "operation": "if_member", + "feature": "ACategorical", + "set": [ + "A", + "B" + ], + "then": { + "operation": "boost", + "score": 5.0 + }, + "else": { + "operation": "boost", + "score": -6.0 + } + } +] \ No newline at end of file Index: clang-tools-extra/clangd/unittests/model/features.json =================================================================== --- /dev/null +++ clang-tools-extra/clangd/unittests/model/features.json @@ -0,0 +1,16 @@ +[ + { + "name": "ANumber", + "type": "NUMERICAL" + }, + { + "name": "AFloat", + "type": "NUMERICAL" + }, + { + "name": "ACategorical", + "type": "CATEGORICAL", + "enum": "ns1::ns2::TestEnum", + "header": "model/CategoricalFeature.h" + } +] \ No newline at end of file Index: clang-tools-extra/clangd/unittests/model/CategoricalFeature.h =================================================================== --- /dev/null +++ clang-tools-extra/clangd/unittests/model/CategoricalFeature.h @@ -0,0 +1,5 @@ +namespace ns1 { +namespace ns2 { +enum TestEnum { A, B, C, D }; +} // namespace ns2 +} // namespace ns1 \ No newline at end of file Index: clang-tools-extra/clangd/unittests/DecisionForestTests.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clangd/unittests/DecisionForestTests.cpp @@ -0,0 +1,30 @@ + +#include "DecisionForestRuntimeTest.h" +#include "model/CategoricalFeature.h" +#include "gtest/gtest.h" + +namespace clangd { +namespace clangd { + +TEST(DecisionForestRuntime, Evaluate) { + using Example = ::ns1::ns2::test::Example; + using Cat = ::ns1::ns2::TestEnum; + using ::ns1::ns2::test::Evaluate; + + Example E; + E.SetANumber(200); // True + E.SetAFloat(0); // True: +10.0 + E.SetACategorical(Cat::A); // True: +5.0 + EXPECT_EQ(Evaluate(E), 15.0); + + E.SetANumber(200); // True + E.SetAFloat(-2.5); // False: -20.0 + E.SetACategorical(Cat::B); // True: +5.0 + EXPECT_EQ(Evaluate(E), -15.0); + + E.SetANumber(100); // False + E.SetACategorical(Cat::C); // True: +3.0, False: -6.0 + EXPECT_EQ(Evaluate(E), -3.0); +} +} // namespace clangd +} // namespace clangd \ No newline at end of file Index: clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -10,6 +10,7 @@ #include "ClangdServer.h" #include "CodeComplete.h" #include "Compiler.h" +#include "CompletionModel.h" #include "Matchers.h" #include "Protocol.h" #include "Quality.h" @@ -47,6 +48,7 @@ using ::testing::IsEmpty; using ::testing::Not; using ::testing::UnorderedElementsAre; +using ContextKind = CodeCompletionContext::Kind; // GMock helpers for matching completion items. MATCHER_P(Named, Name, "") { return arg.Name == Name; } @@ -161,6 +163,16 @@ return S; } +TEST(DecisionForestRuntime, SanityTest) { + using Example = clangd::Example; + using clangd::Evaluate; + Example E1; + E1.SetContextKind(ContextKind::CCC_ArrowMemberAccess); + Example E2; + E2.SetContextKind(ContextKind::CCC_SymbolOrNewName); + EXPECT_GT(Evaluate(E1), Evaluate(E2)); +} + TEST(CompletionTest, Limit) { clangd::CodeCompleteOptions Opts; Opts.Limit = 2; Index: clang-tools-extra/clangd/unittests/CMakeLists.txt =================================================================== --- clang-tools-extra/clangd/unittests/CMakeLists.txt +++ clang-tools-extra/clangd/unittests/CMakeLists.txt @@ -28,6 +28,10 @@ set(REMOTE_TEST_SOURCES remote/MarshallingTests.cpp) endif() +set(DF_COMPILER ${CMAKE_CURRENT_SOURCE_DIR}/../CompletionModelCodegen.py) +include(${CMAKE_CURRENT_SOURCE_DIR}/../CompletionModel.cmake) +df_compile(${CMAKE_CURRENT_SOURCE_DIR}/model DecisionForestRuntimeTest ns1::ns2::test::Example) + add_custom_target(ClangdUnitTests) add_unittest(ClangdUnitTests ClangdTests Annotations.cpp @@ -44,6 +48,7 @@ ConfigCompileTests.cpp ConfigProviderTests.cpp ConfigYAMLTests.cpp + DecisionForestTests.cpp DexTests.cpp DiagnosticsTests.cpp DraftStoreTests.cpp @@ -87,6 +92,7 @@ TweakTesting.cpp URITests.cpp XRefsTests.cpp + ${GENERATED_CC} support/CancellationTests.cpp support/ContextTests.cpp @@ -101,6 +107,10 @@ $<TARGET_OBJECTS:obj.clangDaemonTweaks> ) +target_include_directories(ClangdTests PUBLIC + $<BUILD_INTERFACE:${DF_INCLUDE}> +) + clang_target_link_libraries(ClangdTests PRIVATE clangAST Index: clang-tools-extra/clangd/model/forest.json =================================================================== --- /dev/null +++ clang-tools-extra/clangd/model/forest.json @@ -0,0 +1,18 @@ +[ + { + "operation": "if_member", + "feature": "ContextKind", + "set": [ + "CCC_DotMemberAccess", + "CCC_ArrowMemberAccess" + ], + "then": { + "operation": "boost", + "score": 3.0 + }, + "else": { + "operation": "boost", + "score": 1.0 + } + } +] \ No newline at end of file Index: clang-tools-extra/clangd/model/features.json =================================================================== --- /dev/null +++ clang-tools-extra/clangd/model/features.json @@ -0,0 +1,8 @@ +[ + { + "name": "ContextKind", + "type": "CATEGORICAL", + "enum": "clang::CodeCompletionContext::Kind", + "header": "clang/Sema/CodeCompleteConsumer.h" + } +] \ No newline at end of file Index: clang-tools-extra/clangd/for-review-only/DecisionForestRuntimeTest.h =================================================================== --- /dev/null +++ clang-tools-extra/clangd/for-review-only/DecisionForestRuntimeTest.h @@ -0,0 +1,29 @@ +#ifndef GENERATED_CODE_COMPLETION_MODEL_DECISION_FOREST_RUNTIME_TEST_H +#define GENERATED_CODE_COMPLETION_MODEL_DECISION_FOREST_RUNTIME_TEST_H + #include <cstdint> + +namespace ns1 { +namespace ns2 { +namespace test { + +// Produces an integer that sorts in the same order as F. +// That is: a < b <==> orderEncode(a) < orderEncode(b). +uint32_t OrderEncode(float F); + +class Example { +public: + void SetANumber(float V) { ANumber = OrderEncode(V); } + void SetAFloat(float V) { AFloat = OrderEncode(V); } + void SetACategorical(unsigned V) { ACategorical = 1<<V; } + +private: + uint32_t ANumber = 0; + uint32_t AFloat = 0; + uint32_t ACategorical = 0; + friend float Evaluate(const Example&); +}; +float Evaluate(const Example&); +} // namespace ns1. +} // namespace ns2. +} // namespace test. +#endif // GENERATED_CODE_COMPLETION_MODEL_DECISION_FOREST_RUNTIME_TEST_H \ No newline at end of file Index: clang-tools-extra/clangd/for-review-only/DecisionForestRuntimeTest.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clangd/for-review-only/DecisionForestRuntimeTest.cpp @@ -0,0 +1,48 @@ +#include <cstring> +#include <limits> + +#include "DecisionForestRuntimeTest.h" +#include "llvm/ADT/bit.h" +#include "model/CategoricalFeature.h" + +#define BIT(X) (1<<X) + +namespace ns1 { +namespace ns2 { +namespace test { + +uint32_t OrderEncode(float F) { + static_assert(std::numeric_limits<float>::is_iec559, ""); + constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1); + + // Get the bits of the float. Endianness is the same as for integers. + uint32_t U = llvm::bit_cast<uint32_t>(F); + std::memcpy(&U, &F, sizeof(U)); + // IEEE 754 floats compare like sign-magnitude integers. + if (U & TopBit) // Negative float. + return 0 - U; // Map onto the low half of integers, order reversed. + return U + TopBit; // Positive floats map onto the high half of integers. +} + +float Evaluate(const Example& E) { + float Score = 0; + tree_0: + t0_n0: if(E.ANumber >= 3276275712 /*200.0*/) goto t0_n4; + t0_n1: if(E.ACategorical & (BIT(ns1::ns2::TestEnum::A)|BIT(ns1::ns2::TestEnum::C))) goto t0_n3; + t0_n2: Score += -4.0; goto tree_1; + t0_n3: Score += 3.0; goto tree_1; + t0_n4: if(E.AFloat >= 1082130432 /*-1*/) goto t0_n6; + t0_n5: Score += -20.0; goto tree_1; + t0_n6: Score += 10.0; goto tree_1; + + tree_1: + t1_n0: if(E.ACategorical & (BIT(ns1::ns2::TestEnum::A)|BIT(ns1::ns2::TestEnum::B))) goto t1_n2; + t1_n1: Score += -6.0; goto tree_2; + t1_n2: Score += 5.0; goto tree_2; + + tree_2: // No such tree. + return Score; +} +} // namespace ns1. +} // namespace ns2. +} // namespace test. Index: clang-tools-extra/clangd/for-review-only/CompletionModel.h =================================================================== --- /dev/null +++ clang-tools-extra/clangd/for-review-only/CompletionModel.h @@ -0,0 +1,23 @@ +#ifndef GENERATED_CODE_COMPLETION_MODEL_COMPLETION_MODEL_H +#define GENERATED_CODE_COMPLETION_MODEL_COMPLETION_MODEL_H + #include <cstdint> + +namespace clang { +namespace clangd { + +// Produces an integer that sorts in the same order as F. +// That is: a < b <==> orderEncode(a) < orderEncode(b). +uint32_t OrderEncode(float F); + +class Example { +public: + void SetContextKind(unsigned V) { ContextKind = 1<<V; } + +private: + uint32_t ContextKind = 0; + friend float Evaluate(const Example&); +}; +float Evaluate(const Example&); +} // namespace clang. +} // namespace clangd. +#endif // GENERATED_CODE_COMPLETION_MODEL_COMPLETION_MODEL_H \ No newline at end of file Index: clang-tools-extra/clangd/for-review-only/CompletionModel.cpp =================================================================== --- /dev/null +++ clang-tools-extra/clangd/for-review-only/CompletionModel.cpp @@ -0,0 +1,37 @@ +#include <cstring> +#include <limits> + +#include "CompletionModel.h" +#include "llvm/ADT/bit.h" +#include "clang/Sema/CodeCompleteConsumer.h" + +#define BIT(X) (1<<X) + +namespace clang { +namespace clangd { + +uint32_t OrderEncode(float F) { + static_assert(std::numeric_limits<float>::is_iec559, ""); + constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1); + + // Get the bits of the float. Endianness is the same as for integers. + uint32_t U = llvm::bit_cast<uint32_t>(F); + std::memcpy(&U, &F, sizeof(U)); + // IEEE 754 floats compare like sign-magnitude integers. + if (U & TopBit) // Negative float. + return 0 - U; // Map onto the low half of integers, order reversed. + return U + TopBit; // Positive floats map onto the high half of integers. +} + +float Evaluate(const Example& E) { + float Score = 0; + tree_0: + t0_n0: if(E.ContextKind & (BIT(clang::CodeCompletionContext::Kind::CCC_DotMemberAccess)|BIT(clang::CodeCompletionContext::Kind::CCC_ArrowMemberAccess))) goto t0_n2; + t0_n1: Score += 1.0; goto tree_1; + t0_n2: Score += 3.0; goto tree_1; + + tree_1: // No such tree. + return Score; +} +} // namespace clang. +} // namespace clangd. Index: clang-tools-extra/clangd/CompletionModelCodegen.py =================================================================== --- /dev/null +++ clang-tools-extra/clangd/CompletionModelCodegen.py @@ -0,0 +1,295 @@ +import argparse +import json +import struct +from enum import Enum +from dataclasses import dataclass +from functools import reduce + + +class Feature: + class Type(Enum): + NUMERICAL = 1 + CATEGORICAL = 2 + + def __init__(self, feature_json): + self.name = feature_json['name'] + assert feature_json['type'] in [t.name for t in Feature.Type + ], "Unknown feature type." + self.type = Feature.Type[feature_json['type']] + + if self.type == Feature.Type.CATEGORICAL: + assert 'header' in feature_json, "Header not found in categorical feature." + assert 'enum' in feature_json, "Enum not found in categorical feature." + self.header = feature_json['header'] + self.enum = feature_json['enum'] + + def setter(self): + if self.type == Feature.Type.NUMERICAL: + return "void Set{feature}(float V) {{ {feature} = OrderEncode(V); }}".format( + feature=self.name) + if self.type == Feature.Type.CATEGORICAL: + return "void Set{feature}(unsigned V) {{ {feature} = 1<<V; }}".format( + feature=self.name) + assert False, "Unhandled feature type." + + def member(self): + return "uint32_t {feature} = 0;".format(feature=self.name) + + +def ReadFeatures(features_json: list): + return {f['name']: Feature(f) for f in features_json} + + +def CollectHeaders(features: dict): + return list( + set(f.header for f in filter( + lambda f: f.type == Feature.Type.CATEGORICAL, features.values()))) + + +class CppClass: + def __init__(self, fname, cpp_class): + self.fname = fname + assert not cpp_class.startswith( + "::"), "Do not fully qualify class name." + assert "::" in cpp_class, "Class cannot be defined in global namespace." + ns_and_class = cpp_class.split("::") + self.ns = ns_and_class[0:-1] + self.name = ns_and_class[-1] + + def ns_begin(self): + return ["namespace {ns} {{".format(ns=ns) for ns in self.ns] + + def ns_end(self): + return ["}} // namespace {ns}.".format(ns=ns) for ns in self.ns] + + def header_gaurd(self): + # Convert fname to Upper Snake case. + return "GENERATED_CODE_COMPLETION_MODEL_{}_H".format( + reduce(lambda x, y: x + ('_' if y.isupper() else '') + y, + self.fname).upper()) + + +class Tree: + def __init__(self, json_tree, tree_num: int, node_num: int): + self.operation = json_tree['operation'] + self.tree_num = tree_num + self.node_num = node_num + self.label = "t{0}_n{1}".format(tree_num, node_num) + + if self.operation == 'boost': + self.score = json_tree['score'] + self.size = 1 + return + + self.feature = json_tree['feature'] + if self.operation == 'if_greater': + self.threshold = json_tree['threshold'] + elif self.operation == 'if_member': + self.members = json_tree['set'] + assert isinstance(self.members, list) + else: + raise ValueError("Unknown value for operation: ", self.operation) + + self.false = Tree(json_tree['else'], + tree_num=tree_num, + node_num=node_num + 1) + self.true = Tree(json_tree['then'], + tree_num=tree_num, + node_num=node_num + self.false.size + 1) + self.size = 1 + self.true.size + self.false.size + + def codegen(self, features): + code = [] + if self.node_num == 0: + code.append("tree_{0}:".format(self.tree_num)) + + if self.operation == "boost": + code.append( + "{label}: Score += {score}; goto tree_{next_tree};".format( + label=self.label, + score=self.score, + next_tree=self.tree_num + 1)) + return code + + assert self.feature in features, "Unknown feature {}".format( + self.feature) + if self.operation == "if_greater": + code.append( + "{label}: if(E.{feature} >= {encoded} /*{threshold}*/) goto {true_label};" + .format(label=self.label, + feature=self.feature, + encoded=order_encode(self.threshold), + threshold=self.threshold, + true_label=self.true.label)) + if self.operation == "if_member": + members = '|'.join([ + "BIT({enum}::{member})".format( + enum=features[self.feature].enum, member=member) + for member in self.members + ]) + code.append( + "{label}: if(E.{feature} & ({members})) goto {true_label};". + format(label=self.label, + feature=self.feature, + members=members, + true_label=self.true.label)) + return code + self.false.codegen(features) + self.true.codegen( + features) + + +def ReadDecisionForest(forest_json: list): + forest = [] + tree_num = 0 + for tree_json in forest_json: + forest.append(Tree(tree_json, tree_num=tree_num, node_num=0)) + tree_num += 1 + return forest + + +def gen_header_code(features, cpp_class): + # Header gaurd + code = """#ifndef {gaurd} +#define {gaurd} + #include <cstdint> + +""".format(gaurd=cpp_class.header_gaurd()) + + # Namespace begin + code += "\n".join(cpp_class.ns_begin()) + "\n" + + # Float order encoding. + code += """ +// Produces an integer that sorts in the same order as F. +// That is: a < b <==> orderEncode(a) < orderEncode(b). +uint32_t OrderEncode(float F); + +""" + setters = [f.setter() for f in features.values()] + class_members = [f.member() for f in features.values()] + + # Class. + code += "class {class_name} {{\n".format(class_name=cpp_class.name) + code += "public:\n" + code += " " + "\n ".join(setters) + "\n" + code += "\n" + code += "private:\n" + code += " " + "\n ".join(class_members) + "\n" + + code += " friend float Evaluate(const Example&);\n" + code += "};\n" + code += "float Evaluate(const Example&);" + "\n" + + # Namespace end. + code += "\n".join(cpp_class.ns_end()) + "\n" + code += "#endif // {gaurd}".format(gaurd=cpp_class.header_gaurd()) + return code + + +def order_encode(v: float): + i = struct.unpack('<I', struct.pack('<f', v))[0] + TopBit = 1 << 31 + # IEEE 754 floats compare like sign-magnitude integers. + if (i & TopBit): # Negative float + return (1 << 32) - i # low half of integers, order reversed. + return TopBit + i # top half of integers + + +def gen_evaluate_func(forest: list, features: dict): + # Generate code for Random Forest. + code = "float Evaluate(const Example& E) {\n" + lines = [] + lines.append("float Score = 0;") + for tree in forest: + lines += tree.codegen(features) + lines.append("") + lines.append("tree_{}: // No such tree.".format(len(forest))) + lines.append("return Score;") + + code += " " + "\n ".join(lines) + code += "\n}" + return code + + +def gen_cpp_code(forest: list, features: dict, fname: str, + cpp_class: CppClass): + code = "" + # Headers + angled_include = [ + "cstring", + "limits", + ] + quoted_include = [ + "{}.h".format(fname), + "llvm/ADT/bit.h", + ] + CollectHeaders(features) + code = "\n".join('#include <{h}>'.format(h=h) + for h in angled_include) + "\n\n" + code += "\n".join('#include "{h}"'.format(h=h) + for h in quoted_include) + "\n\n" + code += "#define BIT(X) (1<<X)\n\n" + + # Namespaces Begin + code += "\n".join(cpp_class.ns_begin()) + "\n" + + # Float order encoding. + code += """ +uint32_t OrderEncode(float F) { + static_assert(std::numeric_limits<float>::is_iec559, ""); + constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1); + + // Get the bits of the float. Endianness is the same as for integers. + uint32_t U = llvm::bit_cast<uint32_t>(F); + std::memcpy(&U, &F, sizeof(U)); + // IEEE 754 floats compare like sign-magnitude integers. + if (U & TopBit) // Negative float. + return 0 - U; // Map onto the low half of integers, order reversed. + return U + TopBit; // Positive floats map onto the high half of integers. +} + +""" + code += gen_evaluate_func(forest, features) + "\n" + # Namespaces End + code += "\n".join(cpp_class.ns_end()) + "\n" + return code + + +def main(): + parser = argparse.ArgumentParser('DecisionForestCodegen') + parser.add_argument('--fname', help='output file name.') + parser.add_argument('--output_dir', help='output directory') + parser.add_argument('--model', help='path to model directory') + parser.add_argument( + '--cpp_class', + help= + 'The name of the class (which may be a namespace-qualified) created in generated header.' + ) + ns = parser.parse_args() + + output_dir = ns.output_dir + fname = ns.fname + header_file = "{dir}/{name}.h".format(dir=output_dir, name=fname) + cpp_file = "{dir}/{name}.cpp".format(dir=output_dir, name=fname) + cpp_class = CppClass(fname=fname, cpp_class=ns.cpp_class) + + model_json = "{dir}/forest.json".format(dir=ns.model) + features_json = "{dir}/features.json".format(dir=ns.model) + + with open(features_json) as features_file: + features = Feature.ReadFeatures(json.load(features_file)) + + with open(model_json) as model_file: + forest = Tree.ReadDecisionForest(json.load(model_file)) + + with open(cpp_file, 'w+t') as output_cc: + output_cc.write( + gen_cpp_code(forest=forest, + features=features, + fname=fname, + cpp_class=cpp_class)) + + with open(header_file, 'w+t') as output_h: + output_h.write(gen_header_code(features=features, cpp_class=cpp_class)) + + +if __name__ == '__main__': + main() Index: clang-tools-extra/clangd/CompletionModel.cmake =================================================================== --- /dev/null +++ clang-tools-extra/clangd/CompletionModel.cmake @@ -0,0 +1,31 @@ +# Run the Completion Model Codegenerator on the model in the +# ${model} directory. +# Produces a pair of files called ${fname}.h and ${fname}.cc in the +# ${CMAKE_BINARY_DIR}/generated. The generated header will define a C++ class +# called ${cpp_class} - which may be a namespace-qualified class name. +function(df_compile model fname cpp_class) + set(model_json ${model}/forest.json) + set(model_features ${model}/features.json) + + set(output_dir ${CMAKE_BINARY_DIR}/generated/decision_forest) + set(df_header ${output_dir}/${fname}.h) + set(df_cpp ${output_dir}/${fname}.cpp) + + add_custom_command(OUTPUT ${df_header} ${df_cpp} + COMMAND "${Python3_EXECUTABLE}" ${DF_COMPILER} + --model ${model} + --output_dir ${output_dir} + --fname ${fname} + --cpp_class ${cpp_class} + COMMENT "Generating code completion model runtime..." + DEPENDS ${DF_COMPILER} ${model_json} ${model_features} + VERBATIM ) + + set_source_files_properties(${df_header} PROPERTIES + GENERATED 1) + set_source_files_properties(${df_cpp} PROPERTIES + GENERATED 1 + COMPILE_FLAGS -Wno-unused-label) + set(GENERATED_CC ${df_cpp} PARENT_SCOPE) + set(DF_INCLUDE ${output_dir} PARENT_SCOPE) +endfunction() \ No newline at end of file Index: clang-tools-extra/clangd/CMakeLists.txt =================================================================== --- clang-tools-extra/clangd/CMakeLists.txt +++ clang-tools-extra/clangd/CMakeLists.txt @@ -26,6 +26,10 @@ AllTargetsInfos FrontendOpenMP ) + +set(DF_COMPILER ${CMAKE_CURRENT_SOURCE_DIR}/CompletionModelCodegen.py) +include(${CMAKE_CURRENT_SOURCE_DIR}/CompletionModel.cmake) +df_compile(${CMAKE_CURRENT_SOURCE_DIR}/model CompletionModel clang::clangd::Example) add_clang_library(clangDaemon AST.cpp @@ -69,6 +73,7 @@ TUScheduler.cpp URI.cpp XRefs.cpp + ${GENERATED_CC} index/Background.cpp index/BackgroundIndexLoader.cpp @@ -109,6 +114,10 @@ omp_gen ) +target_include_directories(clangDaemon PUBLIC + $<BUILD_INTERFACE:${DF_INCLUDE}> +) + clang_target_link_libraries(clangDaemon PRIVATE clangAST
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits