526 lines · cpp
1//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//10//===----------------------------------------------------------------------===//11 12#include "clang/Sema/HLSLExternalSemaSource.h"13#include "HLSLBuiltinTypeDeclBuilder.h"14#include "clang/AST/ASTContext.h"15#include "clang/AST/Attr.h"16#include "clang/AST/Decl.h"17#include "clang/AST/DeclCXX.h"18#include "clang/AST/Expr.h"19#include "clang/AST/Type.h"20#include "clang/Basic/SourceLocation.h"21#include "clang/Sema/Lookup.h"22#include "clang/Sema/Sema.h"23#include "clang/Sema/SemaHLSL.h"24#include "llvm/ADT/SmallVector.h"25 26using namespace clang;27using namespace llvm::hlsl;28 29using clang::hlsl::BuiltinTypeDeclBuilder;30 31void HLSLExternalSemaSource::InitializeSema(Sema &S) {32 SemaPtr = &S;33 ASTContext &AST = SemaPtr->getASTContext();34 // If the translation unit has external storage force external decls to load.35 if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())36 (void)AST.getTranslationUnitDecl()->decls_begin();37 38 IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);39 LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);40 NamespaceDecl *PrevDecl = nullptr;41 if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))42 PrevDecl = Result.getAsSingle<NamespaceDecl>();43 HLSLNamespace = NamespaceDecl::Create(44 AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),45 SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);46 HLSLNamespace->setImplicit(true);47 HLSLNamespace->setHasExternalLexicalStorage();48 AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);49 50 // Force external decls in the HLSL namespace to load from the PCH.51 (void)HLSLNamespace->getCanonicalDecl()->decls_begin();52 defineTrivialHLSLTypes();53 defineHLSLTypesWithForwardDeclarations();54 55 // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's56 // built in types inside a namespace, but we are planning to change that in57 // the near future. In order to be source compatible older versions of HLSL58 // will need to implicitly use the hlsl namespace. For now in clang everything59 // will get added to the namespace, and we can remove the using directive for60 // future language versions to match HLSL's evolution.61 auto *UsingDecl = UsingDirectiveDecl::Create(62 AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),63 NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,64 AST.getTranslationUnitDecl());65 66 AST.getTranslationUnitDecl()->addDecl(UsingDecl);67}68 69void HLSLExternalSemaSource::defineHLSLVectorAlias() {70 ASTContext &AST = SemaPtr->getASTContext();71 72 llvm::SmallVector<NamedDecl *> TemplateParams;73 74 auto *TypeParam = TemplateTypeParmDecl::Create(75 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,76 &AST.Idents.get("element", tok::TokenKind::identifier), false, false);77 TypeParam->setDefaultArgument(78 AST, SemaPtr->getTrivialTemplateArgumentLoc(79 TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));80 81 TemplateParams.emplace_back(TypeParam);82 83 auto *SizeParam = NonTypeTemplateParmDecl::Create(84 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,85 &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,86 false, AST.getTrivialTypeSourceInfo(AST.IntTy));87 llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);88 TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,89 /*IsDefaulted=*/true);90 SizeParam->setDefaultArgument(91 AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,92 SourceLocation(), SizeParam));93 TemplateParams.emplace_back(SizeParam);94 95 auto *ParamList =96 TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),97 TemplateParams, SourceLocation(), nullptr);98 99 IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);100 101 QualType AliasType = AST.getDependentSizedExtVectorType(102 AST.getTemplateTypeParmType(0, 0, false, TypeParam),103 DeclRefExpr::Create(104 AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,105 DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),106 AST.IntTy, VK_LValue),107 SourceLocation());108 109 auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),110 SourceLocation(), &II,111 AST.getTrivialTypeSourceInfo(AliasType));112 Record->setImplicit(true);113 114 auto *Template =115 TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),116 Record->getIdentifier(), ParamList, Record);117 118 Record->setDescribedAliasTemplate(Template);119 Template->setImplicit(true);120 Template->setLexicalDeclContext(Record->getDeclContext());121 HLSLNamespace->addDecl(Template);122}123 124void HLSLExternalSemaSource::defineHLSLMatrixAlias() {125 ASTContext &AST = SemaPtr->getASTContext();126 llvm::SmallVector<NamedDecl *> TemplateParams;127 128 auto *TypeParam = TemplateTypeParmDecl::Create(129 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,130 &AST.Idents.get("element", tok::TokenKind::identifier), false, false);131 TypeParam->setDefaultArgument(132 AST, SemaPtr->getTrivialTemplateArgumentLoc(133 TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));134 135 TemplateParams.emplace_back(TypeParam);136 137 // these should be 64 bit to be consistent with other clang matrices.138 auto *RowsParam = NonTypeTemplateParmDecl::Create(139 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,140 &AST.Idents.get("rows_count", tok::TokenKind::identifier), AST.IntTy,141 false, AST.getTrivialTypeSourceInfo(AST.IntTy));142 llvm::APInt RVal(AST.getIntWidth(AST.IntTy), 4);143 TemplateArgument RDefault(AST, llvm::APSInt(std::move(RVal)), AST.IntTy,144 /*IsDefaulted=*/true);145 RowsParam->setDefaultArgument(146 AST, SemaPtr->getTrivialTemplateArgumentLoc(RDefault, AST.IntTy,147 SourceLocation(), RowsParam));148 TemplateParams.emplace_back(RowsParam);149 150 auto *ColsParam = NonTypeTemplateParmDecl::Create(151 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 2,152 &AST.Idents.get("cols_count", tok::TokenKind::identifier), AST.IntTy,153 false, AST.getTrivialTypeSourceInfo(AST.IntTy));154 llvm::APInt CVal(AST.getIntWidth(AST.IntTy), 4);155 TemplateArgument CDefault(AST, llvm::APSInt(std::move(CVal)), AST.IntTy,156 /*IsDefaulted=*/true);157 ColsParam->setDefaultArgument(158 AST, SemaPtr->getTrivialTemplateArgumentLoc(CDefault, AST.IntTy,159 SourceLocation(), ColsParam));160 TemplateParams.emplace_back(ColsParam);161 162 const unsigned MaxMatDim = SemaPtr->getLangOpts().MaxMatrixDimension;163 164 auto *MaxRow = IntegerLiteral::Create(165 AST, llvm::APInt(AST.getIntWidth(AST.IntTy), MaxMatDim), AST.IntTy,166 SourceLocation());167 auto *MaxCol = IntegerLiteral::Create(168 AST, llvm::APInt(AST.getIntWidth(AST.IntTy), MaxMatDim), AST.IntTy,169 SourceLocation());170 171 auto *RowsRef = DeclRefExpr::Create(172 AST, NestedNameSpecifierLoc(), SourceLocation(), RowsParam,173 /*RefersToEnclosingVariableOrCapture*/ false,174 DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),175 AST.IntTy, VK_LValue);176 auto *ColsRef = DeclRefExpr::Create(177 AST, NestedNameSpecifierLoc(), SourceLocation(), ColsParam,178 /*RefersToEnclosingVariableOrCapture*/ false,179 DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),180 AST.IntTy, VK_LValue);181 182 auto *RowsLE = BinaryOperator::Create(AST, RowsRef, MaxRow, BO_LE, AST.BoolTy,183 VK_PRValue, OK_Ordinary,184 SourceLocation(), FPOptionsOverride());185 auto *ColsLE = BinaryOperator::Create(AST, ColsRef, MaxCol, BO_LE, AST.BoolTy,186 VK_PRValue, OK_Ordinary,187 SourceLocation(), FPOptionsOverride());188 189 auto *RequiresExpr = BinaryOperator::Create(190 AST, RowsLE, ColsLE, BO_LAnd, AST.BoolTy, VK_PRValue, OK_Ordinary,191 SourceLocation(), FPOptionsOverride());192 193 auto *ParamList = TemplateParameterList::Create(194 AST, SourceLocation(), SourceLocation(), TemplateParams, SourceLocation(),195 RequiresExpr);196 197 IdentifierInfo &II = AST.Idents.get("matrix", tok::TokenKind::identifier);198 199 QualType AliasType = AST.getDependentSizedMatrixType(200 AST.getTemplateTypeParmType(0, 0, false, TypeParam),201 DeclRefExpr::Create(202 AST, NestedNameSpecifierLoc(), SourceLocation(), RowsParam, false,203 DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),204 AST.IntTy, VK_LValue),205 DeclRefExpr::Create(206 AST, NestedNameSpecifierLoc(), SourceLocation(), ColsParam, false,207 DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),208 AST.IntTy, VK_LValue),209 SourceLocation());210 211 auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),212 SourceLocation(), &II,213 AST.getTrivialTypeSourceInfo(AliasType));214 Record->setImplicit(true);215 216 auto *Template =217 TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),218 Record->getIdentifier(), ParamList, Record);219 220 Record->setDescribedAliasTemplate(Template);221 Template->setImplicit(true);222 Template->setLexicalDeclContext(Record->getDeclContext());223 HLSLNamespace->addDecl(Template);224}225 226void HLSLExternalSemaSource::defineTrivialHLSLTypes() {227 defineHLSLVectorAlias();228 defineHLSLMatrixAlias();229}230 231/// Set up common members and attributes for buffer types232static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,233 ResourceClass RC, bool IsROV,234 bool RawBuffer, bool HasCounter) {235 return BuiltinTypeDeclBuilder(S, Decl)236 .addBufferHandles(RC, IsROV, RawBuffer, HasCounter)237 .addDefaultHandleConstructor()238 .addCopyConstructor()239 .addCopyAssignmentOperator()240 .addStaticInitializationFunctions(HasCounter);241}242 243// This function is responsible for constructing the constraint expression for244// this concept:245// template<typename T> concept is_typed_resource_element_compatible =246// __is_typed_resource_element_compatible<T>;247static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,248 TemplateTypeParmDecl *T) {249 ASTContext &Context = S.getASTContext();250 251 // Obtain the QualType for 'bool'252 QualType BoolTy = Context.BoolTy;253 254 // Create a QualType that points to this TemplateTypeParmDecl255 QualType TType = Context.getTypeDeclType(T);256 257 // Create a TypeSourceInfo for the template type parameter 'T'258 TypeSourceInfo *TTypeSourceInfo =259 Context.getTrivialTypeSourceInfo(TType, NameLoc);260 261 TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create(262 Context, BoolTy, NameLoc, UTT_IsTypedResourceElementCompatible,263 {TTypeSourceInfo}, NameLoc, true);264 265 return TypedResExpr;266}267 268// This function is responsible for constructing the constraint expression for269// this concept:270// template<typename T> concept is_structured_resource_element_compatible =271// !__is_intangible<T> && sizeof(T) >= 1;272static Expr *constructStructuredBufferConstraintExpr(Sema &S,273 SourceLocation NameLoc,274 TemplateTypeParmDecl *T) {275 ASTContext &Context = S.getASTContext();276 277 // Obtain the QualType for 'bool'278 QualType BoolTy = Context.BoolTy;279 280 // Create a QualType that points to this TemplateTypeParmDecl281 QualType TType = Context.getTypeDeclType(T);282 283 // Create a TypeSourceInfo for the template type parameter 'T'284 TypeSourceInfo *TTypeSourceInfo =285 Context.getTrivialTypeSourceInfo(TType, NameLoc);286 287 TypeTraitExpr *IsIntangibleExpr =288 TypeTraitExpr::Create(Context, BoolTy, NameLoc, UTT_IsIntangibleType,289 {TTypeSourceInfo}, NameLoc, true);290 291 // negate IsIntangibleExpr292 UnaryOperator *NotIntangibleExpr = UnaryOperator::Create(293 Context, IsIntangibleExpr, UO_LNot, BoolTy, VK_LValue, OK_Ordinary,294 NameLoc, false, FPOptionsOverride());295 296 // element types also may not be of 0 size297 UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(298 UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc);299 300 // Create a BinaryOperator that checks if the size of the type is not equal to301 // 1 Empty structs have a size of 1 in HLSL, so we need to check for that302 IntegerLiteral *rhs = IntegerLiteral::Create(303 Context, llvm::APInt(Context.getTypeSize(Context.getSizeType()), 1, true),304 Context.getSizeType(), NameLoc);305 306 BinaryOperator *SizeGEQOneExpr =307 BinaryOperator::Create(Context, SizeOfExpr, rhs, BO_GE, BoolTy, VK_LValue,308 OK_Ordinary, NameLoc, FPOptionsOverride());309 310 // Combine the two constraints311 BinaryOperator *CombinedExpr = BinaryOperator::Create(312 Context, NotIntangibleExpr, SizeGEQOneExpr, BO_LAnd, BoolTy, VK_LValue,313 OK_Ordinary, NameLoc, FPOptionsOverride());314 315 return CombinedExpr;316}317 318static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,319 bool isTypedBuffer) {320 ASTContext &Context = S.getASTContext();321 DeclContext *DC = NSD->getDeclContext();322 SourceLocation DeclLoc = SourceLocation();323 324 IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");325 TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(326 Context, NSD->getDeclContext(), DeclLoc, DeclLoc,327 /*D=*/0,328 /*P=*/0,329 /*Id=*/&ElementTypeII,330 /*Typename=*/true,331 /*ParameterPack=*/false);332 333 T->setDeclContext(DC);334 T->setReferenced();335 336 // Create and Attach Template Parameter List to ConceptDecl337 TemplateParameterList *ConceptParams = TemplateParameterList::Create(338 Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr);339 340 DeclarationName DeclName;341 Expr *ConstraintExpr = nullptr;342 343 if (isTypedBuffer) {344 DeclName = DeclarationName(345 &Context.Idents.get("__is_typed_resource_element_compatible"));346 ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T);347 } else {348 DeclName = DeclarationName(349 &Context.Idents.get("__is_structured_resource_element_compatible"));350 ConstraintExpr = constructStructuredBufferConstraintExpr(S, DeclLoc, T);351 }352 353 // Create a ConceptDecl354 ConceptDecl *CD =355 ConceptDecl::Create(Context, NSD->getDeclContext(), DeclLoc, DeclName,356 ConceptParams, ConstraintExpr);357 358 // Attach the template parameter list to the ConceptDecl359 CD->setTemplateParameters(ConceptParams);360 361 // Add the concept declaration to the Translation Unit Decl362 NSD->getDeclContext()->addDecl(CD);363 364 return CD;365}366 367void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {368 CXXRecordDecl *Decl;369 ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(370 *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ true);371 ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(372 *SemaPtr, HLSLNamespace, /*isTypedBuffer*/ false);373 374 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Buffer")375 .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)376 .finalizeForwardDeclaration();377 378 onCompletion(Decl, [this](CXXRecordDecl *Decl) {379 setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,380 /*RawBuffer=*/false, /*HasCounter=*/false)381 .addArraySubscriptOperators()382 .addLoadMethods()383 .addGetDimensionsMethodForBuffer()384 .completeDefinition();385 });386 387 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")388 .addSimpleTemplateParams({"element_type"}, TypedBufferConcept)389 .finalizeForwardDeclaration();390 391 onCompletion(Decl, [this](CXXRecordDecl *Decl) {392 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,393 /*RawBuffer=*/false, /*HasCounter=*/false)394 .addArraySubscriptOperators()395 .addLoadMethods()396 .addGetDimensionsMethodForBuffer()397 .completeDefinition();398 });399 400 Decl =401 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")402 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)403 .finalizeForwardDeclaration();404 onCompletion(Decl, [this](CXXRecordDecl *Decl) {405 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true,406 /*RawBuffer=*/false, /*HasCounter=*/false)407 .addArraySubscriptOperators()408 .addLoadMethods()409 .addGetDimensionsMethodForBuffer()410 .completeDefinition();411 });412 413 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")414 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)415 .finalizeForwardDeclaration();416 onCompletion(Decl, [this](CXXRecordDecl *Decl) {417 setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,418 /*RawBuffer=*/true, /*HasCounter=*/false)419 .addArraySubscriptOperators()420 .addLoadMethods()421 .addGetDimensionsMethodForBuffer()422 .completeDefinition();423 });424 425 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")426 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)427 .finalizeForwardDeclaration();428 onCompletion(Decl, [this](CXXRecordDecl *Decl) {429 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,430 /*RawBuffer=*/true, /*HasCounter=*/true)431 .addArraySubscriptOperators()432 .addLoadMethods()433 .addIncrementCounterMethod()434 .addDecrementCounterMethod()435 .addGetDimensionsMethodForBuffer()436 .completeDefinition();437 });438 439 Decl =440 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")441 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)442 .finalizeForwardDeclaration();443 onCompletion(Decl, [this](CXXRecordDecl *Decl) {444 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,445 /*RawBuffer=*/true, /*HasCounter=*/true)446 .addAppendMethod()447 .addGetDimensionsMethodForBuffer()448 .completeDefinition();449 });450 451 Decl =452 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")453 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)454 .finalizeForwardDeclaration();455 onCompletion(Decl, [this](CXXRecordDecl *Decl) {456 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,457 /*RawBuffer=*/true, /*HasCounter=*/true)458 .addConsumeMethod()459 .addGetDimensionsMethodForBuffer()460 .completeDefinition();461 });462 463 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,464 "RasterizerOrderedStructuredBuffer")465 .addSimpleTemplateParams({"element_type"}, StructuredBufferConcept)466 .finalizeForwardDeclaration();467 onCompletion(Decl, [this](CXXRecordDecl *Decl) {468 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true,469 /*RawBuffer=*/true, /*HasCounter=*/true)470 .addArraySubscriptOperators()471 .addLoadMethods()472 .addIncrementCounterMethod()473 .addDecrementCounterMethod()474 .addGetDimensionsMethodForBuffer()475 .completeDefinition();476 });477 478 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ByteAddressBuffer")479 .finalizeForwardDeclaration();480 onCompletion(Decl, [this](CXXRecordDecl *Decl) {481 setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false,482 /*RawBuffer=*/true, /*HasCounter=*/false)483 .addGetDimensionsMethodForBuffer()484 .completeDefinition();485 });486 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer")487 .finalizeForwardDeclaration();488 onCompletion(Decl, [this](CXXRecordDecl *Decl) {489 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false,490 /*RawBuffer=*/true, /*HasCounter=*/false)491 .addGetDimensionsMethodForBuffer()492 .completeDefinition();493 });494 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,495 "RasterizerOrderedByteAddressBuffer")496 .finalizeForwardDeclaration();497 onCompletion(Decl, [this](CXXRecordDecl *Decl) {498 setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true,499 /*RawBuffer=*/true, /*HasCounter=*/false)500 .addGetDimensionsMethodForBuffer()501 .completeDefinition();502 });503}504 505void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,506 CompletionFunction Fn) {507 if (!Record->isCompleteDefinition())508 Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));509}510 511void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {512 if (!isa<CXXRecordDecl>(Tag))513 return;514 auto Record = cast<CXXRecordDecl>(Tag);515 516 // If this is a specialization, we need to get the underlying templated517 // declaration and complete that.518 if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))519 Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();520 Record = Record->getCanonicalDecl();521 auto It = Completions.find(Record);522 if (It == Completions.end())523 return;524 It->second(Record);525}526