DXIsenseTest.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DXIsenseTest.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides tests for the dxcompiler Intellisense API. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/Test/CompilationResult.h"
  12. #include "dxc/Test/HLSLTestData.h"
  13. #include <stdint.h>
  14. #ifdef _WIN32
  15. #include "WexTestClass.h"
  16. #endif
  17. #include "dxc/Test/HlslTestUtils.h"
  18. #include "dxc/Support/microcom.h"
  19. #ifdef _WIN32
  20. class DXIntellisenseTest {
  21. #else
  22. typedef BSTR CComBSTR;
  23. class DXIntellisenseTest : public ::testing::Test {
  24. #endif
  25. public:
  26. BEGIN_TEST_CLASS(DXIntellisenseTest)
  27. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  28. TEST_METHOD_PROPERTY(L"Priority", L"0")
  29. END_TEST_CLASS()
  30. protected:
  31. TEST_CLASS_SETUP(DXIntellisenseTestClassSetup)
  32. TEST_CLASS_CLEANUP(DXIntellisenseTestClassCleanup)
  33. void GetLocationAt(IDxcTranslationUnit* TU, unsigned line, unsigned col, IDxcSourceLocation** pResult)
  34. {
  35. CComPtr<IDxcFile> file;
  36. VERIFY_SUCCEEDED(TU->GetFile("filename.hlsl", &file));
  37. VERIFY_SUCCEEDED(TU->GetLocation(file, line, col, pResult));
  38. }
  39. void GetCursorAt(IDxcTranslationUnit* TU, unsigned line, unsigned col, IDxcCursor** pResult)
  40. {
  41. CComPtr<IDxcSourceLocation> location;
  42. GetLocationAt(TU, line, col, &location);
  43. VERIFY_SUCCEEDED(TU->GetCursorForLocation(location, pResult));
  44. }
  45. void ExpectCursorAt(IDxcTranslationUnit* TU, unsigned line, unsigned col,
  46. DxcCursorKind expectedKind, _COM_Outptr_opt_ IDxcCursor** pResult = nullptr)
  47. {
  48. CComPtr<IDxcCursor> cursor;
  49. DxcCursorKind actualKind;
  50. GetCursorAt(TU, line, col, &cursor);
  51. VERIFY_SUCCEEDED(cursor->GetKind(&actualKind));
  52. EXPECT_EQ(expectedKind, actualKind);// << " for cursor at " << line << ":" << col;
  53. if (pResult != nullptr)
  54. {
  55. *pResult = cursor.Detach();
  56. }
  57. }
  58. void ExpectQualifiedName(IDxcTranslationUnit* TU, unsigned line, unsigned col, const wchar_t* expectedName)
  59. {
  60. CComPtr<IDxcCursor> cursor;
  61. CComBSTR name;
  62. GetCursorAt(TU, line, col, &cursor);
  63. ASSERT_HRESULT_SUCCEEDED(cursor->GetQualifiedName(FALSE, &name));
  64. EXPECT_STREQW(expectedName, name);// << "qualified name at " << line << ":" << col;
  65. }
  66. void ExpectDeclarationText(IDxcTranslationUnit* TU, unsigned line, unsigned col, const wchar_t* expectedDecl)
  67. {
  68. CComPtr<IDxcCursor> cursor;
  69. CComBSTR name;
  70. GetCursorAt(TU, line, col, &cursor);
  71. DxcCursorFormatting formatting = (DxcCursorFormatting)(
  72. DxcCursorFormatting_IncludeNamespaceKeyword);
  73. ASSERT_HRESULT_SUCCEEDED(cursor->GetFormattedName(formatting, &name));
  74. EXPECT_STREQW(expectedDecl, name);// << "declaration text at " << line << ":" << col;
  75. }
  76. TEST_METHOD(CursorWhenCBufferRefThenFound)
  77. TEST_METHOD(CursorWhenPresumedLocationDifferentFromSpellingLocation)
  78. TEST_METHOD(CursorWhenPresumedLocationSameAsSpellingLocation)
  79. TEST_METHOD(CursorWhenFieldRefThenSimpleNames)
  80. TEST_METHOD(CursorWhenFindAtBodyCallThenMatch)
  81. TEST_METHOD(CursorWhenFindAtGlobalThenMatch)
  82. TEST_METHOD(CursorWhenFindBeforeBodyCallThenMatch)
  83. TEST_METHOD(CursorWhenFindBeforeGlobalThenMatch)
  84. TEST_METHOD(CursorWhenFunctionThenParamsAvailable)
  85. TEST_METHOD(CursorWhenFunctionThenReturnTypeAvailable)
  86. TEST_METHOD(CursorWhenFunctionThenSignatureAvailable)
  87. TEST_METHOD(CursorWhenGlobalVariableThenSimpleNames)
  88. TEST_METHOD(CursorWhenOverloadedIncompleteThenInvisible)
  89. TEST_METHOD(CursorWhenOverloadedResolvedThenDirectSymbol)
  90. TEST_METHOD(CursorWhenReferenceThenDefinitionAvailable)
  91. TEST_METHOD(CursorWhenTypeOfVariableDeclThenNamesHaveType)
  92. TEST_METHOD(CursorWhenVariableRefThenSimpleNames)
  93. TEST_METHOD(CursorWhenVariableUsedThenDeclarationAvailable)
  94. TEST_METHOD(FileWhenSameThenEqual)
  95. TEST_METHOD(FileWhenNotSameThenNotEqual)
  96. TEST_METHOD(InclusionWhenMissingThenError)
  97. TEST_METHOD(InclusionWhenValidThenAvailable)
  98. TEST_METHOD(TUWhenGetFileMissingThenFail)
  99. TEST_METHOD(TUWhenGetFilePresentThenOK)
  100. TEST_METHOD(TUWhenEmptyStructThenErrorIfISense)
  101. TEST_METHOD(TUWhenRegionInactiveMissingThenCountIsZero)
  102. TEST_METHOD(TUWhenRegionInactiveThenEndIsBeforeElseHash)
  103. TEST_METHOD(TUWhenRegionInactiveThenEndIsBeforeEndifHash)
  104. TEST_METHOD(TUWhenRegionInactiveThenStartIsAtIfdefEol)
  105. TEST_METHOD(TUWhenUnsaveFileThenOK)
  106. TEST_METHOD(QualifiedNameClass)
  107. TEST_METHOD(QualifiedNameVariable)
  108. TEST_METHOD(TypeWhenICEThenEval)
  109. TEST_METHOD(CompletionWhenResultsAvailable)
  110. };
  111. bool DXIntellisenseTest::DXIntellisenseTestClassSetup() {
  112. std::shared_ptr<HlslIntellisenseSupport> result = std::make_shared<HlslIntellisenseSupport>();
  113. if (FAILED(result->Initialize()))
  114. return false;
  115. CompilationResult::DefaultHlslSupport = result;
  116. return true;
  117. }
  118. bool DXIntellisenseTest::DXIntellisenseTestClassCleanup() {
  119. CompilationResult::DefaultHlslSupport = nullptr;
  120. return true;
  121. }
  122. TEST_F(DXIntellisenseTest, CursorWhenCBufferRefThenFound) {
  123. char program[] =
  124. "cbuffer MyBuffer {\r\n"
  125. " int a; }\r\n"
  126. "int main() { return\r\n"
  127. "a; }";
  128. CComPtr<IDxcCursor> varRefCursor;
  129. CComPtr<IDxcFile> file;
  130. CComInterfaceArray<IDxcCursor> refs;
  131. CComPtr<IDxcSourceLocation> loc;
  132. unsigned line;
  133. CompilationResult c(CompilationResult::CreateForProgram(program, strlen(program)));
  134. VERIFY_IS_TRUE(c.ParseSucceeded());
  135. ExpectCursorAt(c.TU, 4, 1, DxcCursor_DeclRefExpr, &varRefCursor);
  136. VERIFY_SUCCEEDED(c.TU->GetFile(CompilationResult::getDefaultFileName(), &file));
  137. VERIFY_SUCCEEDED(varRefCursor->FindReferencesInFile(file, 0, 4, refs.size_ref(), refs.data_ref()));
  138. VERIFY_ARE_EQUAL(2U, refs.size());
  139. VERIFY_SUCCEEDED(refs.begin()[0]->GetLocation(&loc));
  140. VERIFY_SUCCEEDED(loc->GetSpellingLocation(nullptr, &line, nullptr, nullptr));
  141. VERIFY_ARE_EQUAL(2U, line);
  142. }
  143. TEST_F(DXIntellisenseTest, CursorWhenPresumedLocationDifferentFromSpellingLocation) {
  144. char program[] =
  145. "#line 21 \"something.h\"\r\n"
  146. "struct MyStruct { };";
  147. CComPtr<IDxcCursor> varCursor;
  148. CComPtr<IDxcSourceLocation> loc;
  149. CComPtr<IDxcFile> spellingFile;
  150. unsigned spellingLine, spellingCol, spellingOffset;
  151. CComHeapPtr<char> presumedFilename;
  152. unsigned presumedLine, presumedCol;
  153. CompilationResult c(CompilationResult::CreateForProgram(program, strlen(program)));
  154. VERIFY_IS_TRUE(c.ParseSucceeded());
  155. ExpectCursorAt(c.TU, 2, 1, DxcCursor_StructDecl, &varCursor);
  156. VERIFY_SUCCEEDED(varCursor->GetLocation(&loc));
  157. VERIFY_SUCCEEDED(loc->GetSpellingLocation(&spellingFile, &spellingLine, &spellingCol, &spellingOffset));
  158. VERIFY_ARE_EQUAL(2u, spellingLine);
  159. VERIFY_ARE_EQUAL(8u, spellingCol);
  160. VERIFY_ARE_EQUAL(31u, spellingOffset);
  161. VERIFY_SUCCEEDED(loc->GetPresumedLocation(&presumedFilename, &presumedLine, &presumedCol));
  162. VERIFY_ARE_EQUAL_STR("something.h", presumedFilename);
  163. VERIFY_ARE_EQUAL(21u, presumedLine);
  164. VERIFY_ARE_EQUAL(8u, presumedCol);
  165. }
  166. TEST_F(DXIntellisenseTest, CursorWhenPresumedLocationSameAsSpellingLocation) {
  167. char program[] = "struct MyStruct { };";
  168. CComPtr<IDxcCursor> varCursor;
  169. CComPtr<IDxcSourceLocation> loc;
  170. CComPtr<IDxcFile> spellingFile;
  171. unsigned spellingLine, spellingCol, spellingOffset;
  172. CComHeapPtr<char> presumedFilename;
  173. unsigned presumedLine, presumedCol;
  174. CompilationResult c(CompilationResult::CreateForProgram(program, strlen(program)));
  175. VERIFY_IS_TRUE(c.ParseSucceeded());
  176. ExpectCursorAt(c.TU, 1, 1, DxcCursor_StructDecl, &varCursor);
  177. VERIFY_SUCCEEDED(varCursor->GetLocation(&loc));
  178. VERIFY_SUCCEEDED(loc->GetSpellingLocation(&spellingFile, &spellingLine, &spellingCol, &spellingOffset));
  179. VERIFY_ARE_EQUAL(1u, spellingLine);
  180. VERIFY_ARE_EQUAL(8u, spellingCol);
  181. VERIFY_ARE_EQUAL(7u, spellingOffset);
  182. VERIFY_SUCCEEDED(loc->GetPresumedLocation(&presumedFilename, &presumedLine, &presumedCol));
  183. VERIFY_ARE_EQUAL_STR(CompilationResult::getDefaultFileName(), presumedFilename);
  184. VERIFY_ARE_EQUAL(1u, presumedLine);
  185. VERIFY_ARE_EQUAL(8u, presumedCol);
  186. }
  187. TEST_F(DXIntellisenseTest, InclusionWhenMissingThenError) {
  188. CComPtr<IDxcIntelliSense> isense;
  189. CComPtr<IDxcIndex> index;
  190. CComPtr<IDxcUnsavedFile> unsaved;
  191. CComPtr<IDxcTranslationUnit> TU;
  192. CComPtr<IDxcDiagnostic> pDiag;
  193. DxcDiagnosticSeverity Severity;
  194. const char main_text[] = "error\r\n#include \"missing.hlsl\"\r\nfloat3 g_global;";
  195. unsigned diagCount;
  196. VERIFY_SUCCEEDED(CompilationResult::DefaultHlslSupport->CreateIntellisense(&isense));
  197. VERIFY_SUCCEEDED(isense->CreateIndex(&index));
  198. VERIFY_SUCCEEDED(isense->CreateUnsavedFile("file.hlsl", main_text, strlen(main_text), &unsaved));
  199. VERIFY_SUCCEEDED(index->ParseTranslationUnit("file.hlsl", nullptr, 0, &unsaved.p, 1,
  200. DxcTranslationUnitFlags_UseCallerThread, &TU));
  201. VERIFY_SUCCEEDED(TU->GetNumDiagnostics(&diagCount));
  202. VERIFY_ARE_EQUAL(1U, diagCount);
  203. VERIFY_SUCCEEDED(TU->GetDiagnostic(0, &pDiag));
  204. VERIFY_SUCCEEDED(pDiag->GetSeverity(&Severity));
  205. VERIFY_IS_TRUE(Severity == DxcDiagnosticSeverity::DxcDiagnostic_Error ||
  206. Severity == DxcDiagnosticSeverity::DxcDiagnostic_Fatal);
  207. }
  208. TEST_F(DXIntellisenseTest, InclusionWhenValidThenAvailable) {
  209. CComPtr<IDxcIntelliSense> isense;
  210. CComPtr<IDxcIndex> index;
  211. CComPtr<IDxcUnsavedFile> unsaved[2];
  212. CComPtr<IDxcTranslationUnit> TU;
  213. CComInterfaceArray<IDxcInclusion> inclusions;
  214. const char main_text[] = "#include \"inc.h\"\r\nfloat4 main() : SV_Target { return FOO; }";
  215. const char unsaved_text[] = "#define FOO 1";
  216. unsigned diagCount;
  217. unsigned expectedIndex = 0;
  218. const char *expectedNames[2] = { "file.hlsl", "./inc.h" };
  219. VERIFY_SUCCEEDED(CompilationResult::DefaultHlslSupport->CreateIntellisense(&isense));
  220. VERIFY_SUCCEEDED(isense->CreateIndex(&index));
  221. VERIFY_SUCCEEDED(isense->CreateUnsavedFile("./inc.h", unsaved_text, strlen(unsaved_text), &unsaved[0]));
  222. VERIFY_SUCCEEDED(isense->CreateUnsavedFile("file.hlsl", main_text, strlen(main_text), &unsaved[1]));
  223. VERIFY_SUCCEEDED(index->ParseTranslationUnit("file.hlsl", nullptr, 0, &unsaved[0].p, 2,
  224. DxcTranslationUnitFlags_UseCallerThread, &TU));
  225. VERIFY_SUCCEEDED(TU->GetNumDiagnostics(&diagCount));
  226. VERIFY_ARE_EQUAL(0U, diagCount);
  227. VERIFY_SUCCEEDED(TU->GetInclusionList(inclusions.size_ref(), inclusions.data_ref()));
  228. VERIFY_ARE_EQUAL(2U, inclusions.size());
  229. for (IDxcInclusion * i : inclusions) {
  230. CComPtr<IDxcFile> file;
  231. CComHeapPtr<char> fileName;
  232. VERIFY_SUCCEEDED(i->GetIncludedFile(&file));
  233. VERIFY_SUCCEEDED(file->GetName(&fileName));
  234. VERIFY_ARE_EQUAL_STR(expectedNames[expectedIndex], fileName.m_pData);
  235. expectedIndex++;
  236. }
  237. }
  238. TEST_F(DXIntellisenseTest, TUWhenGetFileMissingThenFail) {
  239. const char program[] = "int i;";
  240. CompilationResult result = CompilationResult::CreateForProgram(program, strlen(program), nullptr);
  241. VERIFY_IS_TRUE(result.ParseSucceeded());
  242. CComPtr<IDxcFile> file;
  243. VERIFY_FAILED(result.TU->GetFile("unknonwn.txt", &file));
  244. }
  245. TEST_F(DXIntellisenseTest, TUWhenGetFilePresentThenOK) {
  246. const char program[] = "int i;";
  247. CompilationResult result = CompilationResult::CreateForProgram(program, strlen(program), nullptr);
  248. VERIFY_IS_TRUE(result.ParseSucceeded());
  249. CComPtr<IDxcFile> file;
  250. VERIFY_SUCCEEDED(result.TU->GetFile(CompilationResult::getDefaultFileName(), &file));
  251. VERIFY_IS_NOT_NULL(file.p);
  252. }
  253. TEST_F(DXIntellisenseTest, TUWhenEmptyStructThenErrorIfISense) {
  254. // An declaration of the from 'struct S;' is a forward declaration in HLSL
  255. // 2016, but is invalid in HLSL 2015.
  256. const char program[] = "struct S;";
  257. const char programWithDef[] = "struct S { int i; };";
  258. const char *args2015[] = { "-HV", "2015" };
  259. const char *args2016[] = { "-HV", "2016" };
  260. CompilationResult result15WithDef(
  261. CompilationResult::CreateForProgramAndArgs(programWithDef, _countof(programWithDef),
  262. args2015, _countof(args2015), nullptr));
  263. VERIFY_IS_TRUE(result15WithDef.ParseSucceeded());
  264. CompilationResult result15(
  265. CompilationResult::CreateForProgramAndArgs(program, _countof(program),
  266. args2015, _countof(args2015), nullptr));
  267. VERIFY_IS_FALSE(result15.ParseSucceeded());
  268. CompilationResult result16(
  269. CompilationResult::CreateForProgramAndArgs(program, _countof(program),
  270. args2016, _countof(args2016), nullptr));
  271. VERIFY_IS_TRUE(result16.ParseSucceeded());
  272. }
  273. TEST_F(DXIntellisenseTest, TUWhenRegionInactiveMissingThenCountIsZero) {
  274. char program[] = "void foo() { }";
  275. CompilationResult result(
  276. CompilationResult::CreateForProgram(program, _countof(program)));
  277. CComPtr<IDxcFile> file;
  278. unsigned resultCount;
  279. IDxcSourceRange** results;
  280. VERIFY_SUCCEEDED(result.TU->GetFile("filename.hlsl", &file));
  281. VERIFY_SUCCEEDED(result.TU->GetSkippedRanges(file.p, &resultCount, &results));
  282. VERIFY_ARE_EQUAL(0U, resultCount);
  283. VERIFY_IS_NULL(results);
  284. }
  285. TEST_F(DXIntellisenseTest, TUWhenRegionInactiveThenEndIsBeforeElseHash) {
  286. char program[] =
  287. "#ifdef NOT // a comment\r\n"
  288. "int foo() { }\r\n"
  289. "#else // a comment\r\n"
  290. "int bar() { }\r\n"
  291. "#endif // a comment\r\n";
  292. DxcTranslationUnitFlags options = (DxcTranslationUnitFlags)
  293. (DxcTranslationUnitFlags_DetailedPreprocessingRecord | DxcTranslationUnitFlags_UseCallerThread);
  294. CompilationResult result(
  295. CompilationResult::CreateForProgram(program, _countof(program), &options));
  296. CComPtr<IDxcFile> file;
  297. unsigned resultCount;
  298. IDxcSourceRange** results;
  299. VERIFY_SUCCEEDED(result.TU->GetFile("filename.hlsl", &file));
  300. VERIFY_SUCCEEDED(result.TU->GetSkippedRanges(file.p, &resultCount, &results));
  301. ::WEX::TestExecution::DisableVerifyExceptions disable;
  302. VERIFY_ARE_EQUAL(1U, resultCount);
  303. for (unsigned i = 0; i < resultCount; ++i)
  304. {
  305. CComPtr<IDxcSourceLocation> endLoc;
  306. VERIFY_SUCCEEDED(results[i]->GetEnd(&endLoc));
  307. unsigned line, col, offset;
  308. VERIFY_SUCCEEDED(endLoc->GetSpellingLocation(nullptr, &line, &col, &offset));
  309. VERIFY_ARE_EQUAL(3U, line);
  310. VERIFY_ARE_EQUAL(1U, col);
  311. results[i]->Release();
  312. }
  313. CoTaskMemFree(results);
  314. }
  315. TEST_F(DXIntellisenseTest, TUWhenRegionInactiveThenEndIsBeforeEndifHash) {
  316. char program[] =
  317. "#ifdef NOT // a comment\r\n"
  318. "int bar() { }\r\n"
  319. "#endif // a comment\r\n";
  320. DxcTranslationUnitFlags options = (DxcTranslationUnitFlags)
  321. (DxcTranslationUnitFlags_DetailedPreprocessingRecord | DxcTranslationUnitFlags_UseCallerThread);
  322. CompilationResult result(
  323. CompilationResult::CreateForProgram(program, _countof(program), &options));
  324. CComPtr<IDxcFile> file;
  325. unsigned resultCount;
  326. IDxcSourceRange** results;
  327. VERIFY_SUCCEEDED(result.TU->GetFile("filename.hlsl", &file));
  328. VERIFY_SUCCEEDED(result.TU->GetSkippedRanges(file.p, &resultCount, &results));
  329. ::WEX::TestExecution::DisableVerifyExceptions disable;
  330. VERIFY_ARE_EQUAL(1U, resultCount);
  331. for (unsigned i = 0; i < resultCount; ++i)
  332. {
  333. CComPtr<IDxcSourceLocation> endLoc;
  334. VERIFY_SUCCEEDED(results[i]->GetEnd(&endLoc));
  335. unsigned line, col, offset;
  336. VERIFY_SUCCEEDED(endLoc->GetSpellingLocation(nullptr, &line, &col, &offset));
  337. VERIFY_ARE_EQUAL(3U, line);
  338. VERIFY_ARE_EQUAL(1U, col);
  339. results[i]->Release();
  340. }
  341. CoTaskMemFree(results);
  342. }
  343. TEST_F(DXIntellisenseTest, TUWhenRegionInactiveThenStartIsAtIfdefEol) {
  344. char program[] =
  345. "#ifdef NOT // a comment\r\n"
  346. "int foo() { }\r\n"
  347. "#else // a comment\r\n"
  348. "int bar() { }\r\n"
  349. "#endif // a comment\r\n";
  350. DxcTranslationUnitFlags options = (DxcTranslationUnitFlags)
  351. (DxcTranslationUnitFlags_DetailedPreprocessingRecord | DxcTranslationUnitFlags_UseCallerThread);
  352. CompilationResult result(
  353. CompilationResult::CreateForProgram(program, _countof(program), &options));
  354. CComPtr<IDxcFile> file;
  355. unsigned resultCount;
  356. IDxcSourceRange** results;
  357. VERIFY_SUCCEEDED(result.TU->GetFile("filename.hlsl", &file));
  358. VERIFY_SUCCEEDED(result.TU->GetSkippedRanges(file.p, &resultCount, &results));
  359. ::WEX::TestExecution::DisableVerifyExceptions disable;
  360. VERIFY_ARE_EQUAL(1U, resultCount);
  361. for (unsigned i = 0; i < resultCount; ++i)
  362. {
  363. CComPtr<IDxcSourceLocation> startLoc;
  364. VERIFY_SUCCEEDED(results[i]->GetStart(&startLoc));
  365. unsigned line, col, offset;
  366. VERIFY_SUCCEEDED(startLoc->GetSpellingLocation(nullptr, &line, &col, &offset));
  367. VERIFY_ARE_EQUAL(1U, line);
  368. VERIFY_ARE_EQUAL(24U, col);
  369. results[i]->Release();
  370. }
  371. CoTaskMemFree(results);
  372. }
  373. std::ostream& operator<<(std::ostream& os, CComPtr<IDxcSourceLocation>& loc)
  374. {
  375. CComPtr<IDxcFile> locFile;
  376. unsigned locLine, locCol, locOffset;
  377. loc->GetSpellingLocation(&locFile, &locLine, &locCol, &locOffset);
  378. os << locLine << ':' << locCol << '@' << locOffset;
  379. return os;
  380. }
  381. std::wostream& operator<<(std::wostream& os, CComPtr<IDxcSourceLocation>& loc)
  382. {
  383. CComPtr<IDxcFile> locFile;
  384. unsigned locLine, locCol, locOffset;
  385. loc->GetSpellingLocation(&locFile, &locLine, &locCol, &locOffset);
  386. os << locLine << L':' << locCol << L'@' << locOffset;
  387. return os;
  388. }
  389. TEST_F(DXIntellisenseTest, TUWhenUnsaveFileThenOK) {
  390. // Verify that an unsaved file using the library-provided implementation still works.
  391. const char fileName[] = "filename.hlsl";
  392. char program[] =
  393. "[numthreads(1, 1, 1)]\r\n"
  394. "void main( uint3 DTid : SV_DispatchThreadID )\r\n"
  395. "{\r\n"
  396. "}";
  397. bool useBuiltInValues[] = { false, true };
  398. HlslIntellisenseSupport support;
  399. VERIFY_SUCCEEDED(support.Initialize());
  400. for (bool useBuiltIn : useBuiltInValues) {
  401. CComPtr<IDxcIntelliSense> isense;
  402. CComPtr<IDxcIndex> tuIndex;
  403. CComPtr<IDxcTranslationUnit> tu;
  404. CComPtr<IDxcUnsavedFile> unsavedFile;
  405. DxcTranslationUnitFlags localOptions;
  406. const char **commandLineArgs = nullptr;
  407. int commandLineArgsCount = 0;
  408. VERIFY_SUCCEEDED(support.CreateIntellisense(&isense));
  409. VERIFY_SUCCEEDED(isense->CreateIndex(&tuIndex));
  410. VERIFY_SUCCEEDED(isense->GetDefaultEditingTUOptions(&localOptions));
  411. if (useBuiltIn)
  412. VERIFY_SUCCEEDED(isense->CreateUnsavedFile(fileName, program, strlen(program), &unsavedFile));
  413. else
  414. VERIFY_SUCCEEDED(TrivialDxcUnsavedFile::Create(fileName, program, &unsavedFile));
  415. VERIFY_SUCCEEDED(tuIndex->ParseTranslationUnit(fileName,
  416. commandLineArgs, commandLineArgsCount,
  417. &(unsavedFile.p), 1, localOptions, &tu));
  418. // No errors expected.
  419. unsigned numDiagnostics;
  420. VERIFY_SUCCEEDED(tu->GetNumDiagnostics(&numDiagnostics));
  421. VERIFY_ARE_EQUAL(0U, numDiagnostics);
  422. CComPtr<IDxcCursor> tuCursor;
  423. CComInterfaceArray<IDxcCursor> cursors;
  424. VERIFY_SUCCEEDED(tu->GetCursor(&tuCursor));
  425. VERIFY_SUCCEEDED(tuCursor->GetChildren(0, 20, cursors.size_ref(), cursors.data_ref()));
  426. std::wstringstream offsetStream;
  427. for (IDxcCursor *pCursor : cursors) {
  428. CComPtr<IDxcSourceRange> range;
  429. CComPtr<IDxcSourceLocation> location;
  430. CComPtr<IDxcSourceLocation> rangeStart, rangeEnd;
  431. CComBSTR name;
  432. VERIFY_SUCCEEDED(pCursor->GetExtent(&range));
  433. VERIFY_SUCCEEDED(range->GetStart(&rangeStart));
  434. VERIFY_SUCCEEDED(range->GetEnd(&rangeEnd));
  435. VERIFY_SUCCEEDED(pCursor->GetDisplayName(&name));
  436. VERIFY_SUCCEEDED(pCursor->GetLocation(&location));
  437. offsetStream << (LPWSTR)name << " - spelling " << location <<
  438. " - extent " << rangeStart << " .. " << rangeEnd << std::endl;
  439. }
  440. // Format for a location is line:col@offset
  441. VERIFY_ARE_EQUAL_WSTR(
  442. L"main(uint3) - spelling 2:6@28 - extent 2:1@23 .. 4:2@74\n",
  443. offsetStream.str().c_str());
  444. }
  445. }
  446. TEST_F(DXIntellisenseTest, QualifiedNameClass) {
  447. char program[] =
  448. "class TheClass {\r\n"
  449. "};\r\n"
  450. "TheClass C;";
  451. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  452. ExpectQualifiedName(result.TU, 3, 1, L"TheClass");
  453. }
  454. TEST_F(DXIntellisenseTest, CursorWhenGlobalVariableThenSimpleNames) {
  455. char program[] =
  456. "namespace Ns { class TheClass {\r\n"
  457. "}; }\r\n"
  458. "Ns::TheClass C;";
  459. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  460. // Qualified name does not include type.
  461. ExpectQualifiedName(result.TU, 3, 14, L"C");
  462. // Decalaration name includes type.
  463. ExpectDeclarationText(result.TU, 3, 14, L"Ns::TheClass C");
  464. // Semicolon is empty.
  465. ExpectQualifiedName(result.TU, 3, 15, L"");
  466. }
  467. TEST_F(DXIntellisenseTest, CursorWhenTypeOfVariableDeclThenNamesHaveType) {
  468. char program[] =
  469. "namespace Ns { class TheClass {\r\n"
  470. "}; }\r\n"
  471. "Ns::TheClass C;";
  472. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  473. ExpectQualifiedName(result.TU, 3, 1, L"Ns");
  474. ExpectDeclarationText(result.TU, 3, 1, L"namespace Ns");
  475. ExpectQualifiedName(result.TU, 3, 6, L"Ns::TheClass");
  476. ExpectDeclarationText(result.TU, 3, 6, L"class Ns::TheClass");
  477. }
  478. TEST_F(DXIntellisenseTest, CursorWhenVariableRefThenSimpleNames) {
  479. char program[] =
  480. "namespace Ns { class TheClass {\r\n"
  481. "public: int f;\r\n"
  482. "}; }\r\n"
  483. "void fn() {\r\n"
  484. "Ns::TheClass C;\r\n"
  485. "C.f = 1;\r\n"
  486. "}";
  487. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  488. ExpectCursorAt(result.TU, 6, 1, DxcCursor_DeclRefExpr);
  489. ExpectQualifiedName(result.TU, 6, 1, L"C");
  490. }
  491. TEST_F(DXIntellisenseTest, CursorWhenFieldRefThenSimpleNames) {
  492. char program[] =
  493. "namespace Ns { class TheClass {\r\n"
  494. "public: int f;\r\n"
  495. "}; }\r\n"
  496. "void fn() {\r\n"
  497. "Ns::TheClass C;\r\n"
  498. "C.f = 1;\r\n"
  499. "}";
  500. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  501. ExpectQualifiedName(result.TU, 6, 3, L"int f");
  502. }
  503. TEST_F(DXIntellisenseTest, QualifiedNameVariable) {
  504. char program[] =
  505. "namespace Ns { class TheClass {\r\n"
  506. "}; }\r\n"
  507. "Ns::TheClass C;";
  508. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  509. ExpectQualifiedName(result.TU, 3, 14, L"C");
  510. }
  511. TEST_F(DXIntellisenseTest, CursorWhenOverloadedResolvedThenDirectSymbol) {
  512. char program[] =
  513. "int abc(int);\r\n"
  514. "float abc(float);\r\n"
  515. "void foo() {\r\n"
  516. "int i = abc(123);\r\n"
  517. "}\r\n";
  518. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  519. CComPtr<IDxcCursor> cursor;
  520. GetCursorAt(result.TU, 4, 10, &cursor);
  521. DxcCursorKind kind;
  522. // 'abc' in 'abc(123)' is an expression that refers to a declaration.
  523. ASSERT_HRESULT_SUCCEEDED(cursor->GetKind(&kind));
  524. EXPECT_EQ(DxcCursor_DeclRefExpr, kind);
  525. // The referenced declaration is a function declaration.
  526. CComPtr<IDxcCursor> referenced;
  527. ASSERT_HRESULT_SUCCEEDED(cursor->GetReferencedCursor(&referenced));
  528. ASSERT_HRESULT_SUCCEEDED(referenced->GetKind(&kind));
  529. EXPECT_EQ(DxcCursor_FunctionDecl, kind);
  530. }
  531. TEST_F(DXIntellisenseTest, CursorWhenOverloadedIncompleteThenInvisible) {
  532. char program[] =
  533. "int abc(int);\r\n"
  534. "float abc(float);\r\n"
  535. "void foo() {\r\n"
  536. "int i = abc();\r\n"
  537. "}";
  538. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  539. CComPtr<IDxcCursor> cursor;
  540. GetCursorAt(result.TU, 4, 10, &cursor);
  541. DxcCursorKind kind;
  542. // 'abc' in 'abc()' is just part of the declaration - it's not a valid standalone entity
  543. ASSERT_HRESULT_SUCCEEDED(cursor->GetKind(&kind));
  544. EXPECT_EQ(DxcCursor_DeclStmt, kind);
  545. // The child of the declaration statement is the declaration.
  546. CComPtr<IDxcCursor> decl;
  547. ASSERT_HRESULT_SUCCEEDED(GetFirstChildFromCursor(cursor, &decl));
  548. ASSERT_HRESULT_SUCCEEDED(decl->GetKind(&kind));
  549. EXPECT_EQ(DxcCursor_VarDecl, kind);
  550. }
  551. TEST_F(DXIntellisenseTest, CursorWhenVariableUsedThenDeclarationAvailable) {
  552. char program[] =
  553. "int foo() {\r\n"
  554. "int i = 1;\r\n"
  555. "return i;\r\n"
  556. "}";
  557. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  558. CComPtr<IDxcCursor> cursor;
  559. // 'abc' in 'abc()' is just part of the declaration - it's not a valid standalone entity
  560. ExpectCursorAt(result.TU, 3, 8, DxcCursor_DeclRefExpr, &cursor);
  561. // The referenced declaration is a variable declaration.
  562. CComPtr<IDxcCursor> referenced;
  563. DxcCursorKind kind;
  564. ASSERT_HRESULT_SUCCEEDED(cursor->GetReferencedCursor(&referenced));
  565. ASSERT_HRESULT_SUCCEEDED(referenced->GetKind(&kind));
  566. EXPECT_EQ(DxcCursor_VarDecl, kind);
  567. CComBSTR name;
  568. ASSERT_HRESULT_SUCCEEDED(referenced->GetFormattedName(DxcCursorFormatting_Default, &name));
  569. EXPECT_STREQW(L"i", (LPWSTR)name);
  570. }
  571. // TODO: get a referenced local variable as 'int localVar';
  572. // TODO: get a referenced type as 'class Something';
  573. // TODO: having the caret on a function name in definition, highlights calls to it
  574. // TODO: get a class name without the template arguments
  575. // TODO: get a class name with ftemplate arguments
  576. // TODO: code completion for a built-in function
  577. // TODO: code completion for a built-in method
  578. TEST_F(DXIntellisenseTest, CursorWhenFunctionThenSignatureAvailable)
  579. {
  580. char program[] =
  581. "int myfunc(int a, float b) { return a + b; }\r\n"
  582. "int foo() {\r\n"
  583. "myfunc(1, 2.0f);\r\n"
  584. "}";
  585. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  586. CComPtr<IDxcCursor> cursor;
  587. ExpectCursorAt(result.TU, 3, 1, DxcCursor_DeclRefExpr, &cursor);
  588. // TODO - how to get signature?
  589. }
  590. TEST_F(DXIntellisenseTest, CursorWhenFunctionThenParamsAvailable)
  591. {
  592. char program[] =
  593. "int myfunc(int a, float b) { return a + b; }\r\n"
  594. "int foo() {\r\n"
  595. "myfunc(1, 2.0f);\r\n"
  596. "}";
  597. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  598. CComPtr<IDxcCursor> cursor;
  599. ExpectCursorAt(result.TU, 3, 1, DxcCursor_DeclRefExpr, &cursor);
  600. int argCount;
  601. VERIFY_SUCCEEDED(cursor->GetNumArguments(&argCount));
  602. VERIFY_ARE_EQUAL(-1, argCount); // The reference doesn't have the argument count - we need to resolve to func decl
  603. // TODO - how to get signature?
  604. }
  605. TEST_F(DXIntellisenseTest, CursorWhenFunctionThenReturnTypeAvailable)
  606. {
  607. char program[] =
  608. "int myfunc(int a, float b) { return a + b; }\r\n"
  609. "int foo() {\r\n"
  610. "myfunc(1, 2.0f);\r\n"
  611. "}";
  612. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  613. CComPtr<IDxcCursor> cursor;
  614. ExpectCursorAt(result.TU, 3, 1, DxcCursor_DeclRefExpr, &cursor);
  615. // TODO - how to get signature?
  616. }
  617. TEST_F(DXIntellisenseTest, CursorWhenReferenceThenDefinitionAvailable)
  618. {
  619. char program[] =
  620. "int myfunc(int a, float b) { return a + b; }\r\n"
  621. "int foo() {\r\n"
  622. "myfunc(1, 2.0f);\r\n"
  623. "}";
  624. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  625. CComPtr<IDxcCursor> cursor;
  626. CComPtr<IDxcCursor> defCursor;
  627. CComPtr<IDxcSourceLocation> defLocation;
  628. CComPtr<IDxcFile> defFile;
  629. unsigned line, col, offset;
  630. ExpectCursorAt(result.TU, 3, 1, DxcCursor_DeclRefExpr, &cursor);
  631. VERIFY_SUCCEEDED(cursor->GetDefinitionCursor(&defCursor));
  632. VERIFY_IS_NOT_NULL(defCursor.p);
  633. DxcCursorKind kind;
  634. VERIFY_SUCCEEDED(defCursor->GetKind(&kind));
  635. VERIFY_ARE_EQUAL(DxcCursor_FunctionDecl, kind);
  636. VERIFY_SUCCEEDED(defCursor->GetLocation(&defLocation));
  637. VERIFY_SUCCEEDED(defLocation->GetSpellingLocation(&defFile, &line, &col, &offset));
  638. VERIFY_ARE_EQUAL(1U, line);
  639. VERIFY_ARE_EQUAL(5U, col); // Points to 'myfunc'
  640. VERIFY_ARE_EQUAL(4U, offset); // Offset is zero-based
  641. }
  642. TEST_F(DXIntellisenseTest,CursorWhenFindAtBodyCallThenMatch)
  643. {
  644. char program[] =
  645. "int f();\r\n"
  646. "int main() {\r\n"
  647. " f(); }";
  648. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  649. CComPtr<IDxcCursor> cursor;
  650. ExpectCursorAt(result.TU, 3, 3, DxcCursor_DeclRefExpr, &cursor);
  651. }
  652. TEST_F(DXIntellisenseTest, CursorWhenFindAtGlobalThenMatch)
  653. {
  654. char program[] = "int a;";
  655. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  656. CComPtr<IDxcCursor> cursor;
  657. ExpectCursorAt(result.TU, 1, 4, DxcCursor_VarDecl, &cursor);
  658. }
  659. TEST_F(DXIntellisenseTest, CursorWhenFindBeforeBodyCallThenMatch)
  660. {
  661. char program[] =
  662. "int f();\r\n"
  663. "int main() {\r\n"
  664. " f(); }";
  665. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  666. CComPtr<IDxcCursor> cursor;
  667. ExpectCursorAt(result.TU, 3, 1, DxcCursor_CompoundStmt, &cursor);
  668. CComPtr<IDxcCursor> snappedCursor;
  669. CComPtr<IDxcSourceLocation> location;
  670. DxcCursorKind cursorKind;
  671. GetLocationAt(result.TU, 3, 1, &location);
  672. VERIFY_SUCCEEDED(cursor->GetSnappedChild(location, &snappedCursor));
  673. VERIFY_IS_NOT_NULL(snappedCursor.p);
  674. VERIFY_SUCCEEDED(snappedCursor->GetKind(&cursorKind));
  675. VERIFY_ARE_EQUAL(DxcCursor_DeclRefExpr, cursorKind);
  676. }
  677. TEST_F(DXIntellisenseTest, CursorWhenFindBeforeGlobalThenMatch)
  678. {
  679. char program[] = " int a;";
  680. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  681. CComPtr<IDxcCursor> cursor;
  682. ExpectCursorAt(result.TU, 1, 1, DxcCursor_NoDeclFound, &cursor);
  683. cursor.Release();
  684. CComPtr<IDxcCursor> snappedCursor;
  685. CComPtr<IDxcSourceLocation> location;
  686. DxcCursorKind cursorKind;
  687. GetLocationAt(result.TU, 1, 1, &location);
  688. VERIFY_SUCCEEDED(result.TU->GetCursor(&cursor));
  689. VERIFY_SUCCEEDED(cursor->GetSnappedChild(location, &snappedCursor));
  690. VERIFY_IS_NOT_NULL(snappedCursor.p);
  691. VERIFY_SUCCEEDED(snappedCursor->GetKind(&cursorKind));
  692. VERIFY_ARE_EQUAL(DxcCursor_VarDecl, cursorKind);
  693. }
  694. TEST_F(DXIntellisenseTest, FileWhenSameThenEqual)
  695. {
  696. char program[] = "int a;\r\nint b;";
  697. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  698. CComPtr<IDxcSourceLocation> location0, location1;
  699. CComPtr<IDxcFile> file0, file1;
  700. unsigned line, col, offset;
  701. BOOL isEqual;
  702. GetLocationAt(result.TU, 1, 1, &location0);
  703. GetLocationAt(result.TU, 2, 1, &location1);
  704. VERIFY_SUCCEEDED(location0->GetSpellingLocation(&file0, &line, &col, &offset));
  705. VERIFY_SUCCEEDED(location1->GetSpellingLocation(&file1, &line, &col, &offset));
  706. VERIFY_SUCCEEDED(file0->IsEqualTo(file1, &isEqual));
  707. VERIFY_ARE_EQUAL(TRUE, isEqual);
  708. }
  709. TEST_F(DXIntellisenseTest, FileWhenNotSameThenNotEqual)
  710. {
  711. char program[] = "int a;\r\nint b;";
  712. CompilationResult result0(CompilationResult::CreateForProgram(program, _countof(program)));
  713. CompilationResult result1(CompilationResult::CreateForProgram(program, _countof(program)));
  714. CComPtr<IDxcSourceLocation> location0, location1;
  715. CComPtr<IDxcFile> file0, file1;
  716. unsigned line, col, offset;
  717. BOOL isEqual;
  718. GetLocationAt(result0.TU, 1, 1, &location0);
  719. GetLocationAt(result1.TU, 1, 1, &location1);
  720. VERIFY_SUCCEEDED(location0->GetSpellingLocation(&file0, &line, &col, &offset));
  721. VERIFY_SUCCEEDED(location1->GetSpellingLocation(&file1, &line, &col, &offset));
  722. VERIFY_SUCCEEDED(file0->IsEqualTo(file1, &isEqual));
  723. VERIFY_ARE_EQUAL(FALSE, isEqual);
  724. }
  725. TEST_F(DXIntellisenseTest, TypeWhenICEThenEval)
  726. {
  727. // When an ICE is present in a declaration, it appears in the name.
  728. char program[] =
  729. "float c[(1, 2)];\r\n"
  730. "float main() : SV_Target\r\n"
  731. "{ return c[0]; }";
  732. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  733. VERIFY_IS_TRUE(result.ParseSucceeded());
  734. CComPtr<IDxcCursor> cCursor;
  735. ExpectCursorAt(result.TU, 1, 7, DxcCursor_VarDecl, &cCursor);
  736. CComPtr<IDxcType> typeCursor;
  737. VERIFY_SUCCEEDED(cCursor->GetCursorType(&typeCursor));
  738. CComHeapPtr<char> name;
  739. VERIFY_SUCCEEDED(typeCursor->GetSpelling(&name));
  740. VERIFY_ARE_EQUAL_STR("const float [2]", name); // global variables converted to const by default
  741. }
  742. TEST_F(DXIntellisenseTest, CompletionWhenResultsAvailable)
  743. {
  744. char program[] =
  745. "struct MyStruct {};"
  746. "MyStr";
  747. CompilationResult result(CompilationResult::CreateForProgram(program, _countof(program)));
  748. VERIFY_IS_FALSE(result.ParseSucceeded());
  749. const char* fileName = "filename.hlsl";
  750. CComPtr<IDxcUnsavedFile> unsavedFile;
  751. VERIFY_SUCCEEDED(TrivialDxcUnsavedFile::Create(fileName, program, &unsavedFile));
  752. CComPtr<IDxcCodeCompleteResults> codeCompleteResults;
  753. VERIFY_SUCCEEDED(result.TU->CodeCompleteAt(fileName, 2, 1, &unsavedFile.p, 1, DxcCodeCompleteFlags_None, &codeCompleteResults));
  754. unsigned numResults;
  755. VERIFY_SUCCEEDED(codeCompleteResults->GetNumResults(&numResults));
  756. VERIFY_IS_GREATER_THAN_OR_EQUAL(numResults, 1u);
  757. CComPtr<IDxcCompletionResult> completionResult;
  758. VERIFY_SUCCEEDED(codeCompleteResults->GetResultAt(0, &completionResult));
  759. DxcCursorKind completionResultCursorKind;
  760. VERIFY_SUCCEEDED(completionResult->GetCursorKind(&completionResultCursorKind));
  761. VERIFY_ARE_EQUAL(DxcCursor_StructDecl, completionResultCursorKind);
  762. CComPtr<IDxcCompletionString> completionString;
  763. VERIFY_SUCCEEDED(completionResult->GetCompletionString(&completionString));
  764. unsigned numCompletionChunks;
  765. VERIFY_SUCCEEDED(completionString->GetNumCompletionChunks(&numCompletionChunks));
  766. VERIFY_ARE_EQUAL(1u, numCompletionChunks);
  767. DxcCompletionChunkKind completionChunkKind;
  768. VERIFY_SUCCEEDED(completionString->GetCompletionChunkKind(0, &completionChunkKind));
  769. VERIFY_ARE_EQUAL(DxcCompletionChunk_TypedText, completionChunkKind);
  770. CComHeapPtr<char> completionChunkText;
  771. VERIFY_SUCCEEDED(completionString->GetCompletionChunkText(0, &completionChunkText));
  772. VERIFY_ARE_EQUAL_STR("MyStruct", completionChunkText);
  773. }