1import os 2 3from clang.cindex import Config, TranslationUnit 4 5if "CLANG_LIBRARY_PATH" in os.environ: 6 Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"]) 7 8import unittest 9from pathlib import Path 10 11 12class TestCodeCompletion(unittest.TestCase): 13 def check_completion_results(self, cr, expected): 14 self.assertIsNotNone(cr) 15 self.assertEqual(len(cr.diagnostics), 0) 16 17 completions = [str(c) for c in cr.results] 18 19 for c in expected: 20 self.assertIn(c, completions) 21 22 def test_code_complete(self): 23 files = [ 24 ( 25 "fake.c", 26 """ 27/// Aaa. 28int test1; 29 30/// Bbb. 31void test2(void); 32 33void f() { 34 35} 36""", 37 ) 38 ] 39 40 tu = TranslationUnit.from_source( 41 "fake.c", 42 ["-std=c99"], 43 unsaved_files=files, 44 options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION, 45 ) 46 47 cr = tu.codeComplete( 48 "fake.c", 9, 1, unsaved_files=files, include_brief_comments=True 49 ) 50 51 expected = [ 52 "{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.", 53 "{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.", 54 "{'return', TypedText} | {';', SemiColon} || Priority: 40 || Availability: Available || Brief comment: ", 55 ] 56 self.check_completion_results(cr, expected) 57 58 def test_code_complete_pathlike(self): 59 files = [ 60 ( 61 Path("fake.c"), 62 """ 63/// Aaa. 64int test1; 65 66/// Bbb. 67void test2(void); 68 69void f() { 70 71} 72""", 73 ) 74 ] 75 76 tu = TranslationUnit.from_source( 77 Path("fake.c"), 78 ["-std=c99"], 79 unsaved_files=files, 80 options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION, 81 ) 82 83 cr = tu.codeComplete( 84 Path("fake.c"), 85 9, 86 1, 87 unsaved_files=files, 88 include_brief_comments=True, 89 ) 90 91 expected = [ 92 "{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.", 93 "{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.", 94 "{'return', TypedText} | {';', SemiColon} || Priority: 40 || Availability: Available || Brief comment: ", 95 ] 96 self.check_completion_results(cr, expected) 97 98 def test_code_complete_availability(self): 99 files = [ 100 ( 101 "fake.cpp", 102 """ 103class P { 104protected: 105 int member; 106}; 107 108class Q : public P { 109public: 110 using P::member; 111}; 112 113void f(P x, Q y) { 114 x.; // member is inaccessible 115 y.; // member is accessible 116} 117""", 118 ) 119 ] 120 121 tu = TranslationUnit.from_source( 122 "fake.cpp", ["-std=c++98"], unsaved_files=files 123 ) 124 125 cr = tu.codeComplete("fake.cpp", 12, 5, unsaved_files=files) 126 127 expected = [ 128 "{'const', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", 129 "{'volatile', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", 130 "{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: ", 131 "{'P', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", 132 "{'Q', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", 133 ] 134 self.check_completion_results(cr, expected) 135 136 cr = tu.codeComplete("fake.cpp", 13, 5, unsaved_files=files) 137 expected = [ 138 "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: ", 139 "{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: ", 140 "{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: ", 141 "{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: ", 142 ] 143 self.check_completion_results(cr, expected) 144