blob: 79e1a7ec53c0c734a13ceb7e7352f04cf366d0d6 [file] [log] [blame] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// CompilationResult.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// This file provides a class to parse a translation unit and return the //
// diagnostic results and AST tree. //
// //
///////////////////////////////////////////////////////////////////////////////
#include <memory>
#include <vector>
#include <string>
#include <iostream>
#include <cassert>
#include <sstream>
#include <algorithm>
#include <atomic>
#include "dxc/Support/WinIncludes.h"
#include "dxc/dxcapi.h"
#include "dxc/dxcisense.h"
#include "dxc/Support/dxcapi.use.h"
#include "llvm/Support/Atomic.h"
inline HRESULT IFE(HRESULT hr) {
if (FAILED(hr)) {
throw std::runtime_error("COM call failed");
}
return hr;
}
inline HRESULT GetFirstChildFromCursor(IDxcCursor *cursor,
IDxcCursor **pResult) {
HRESULT hr;
IDxcCursor **children = nullptr;
unsigned childrenCount;
hr = cursor->GetChildren(0, 1, &childrenCount, &children);
if (SUCCEEDED(hr) && childrenCount == 1) {
*pResult = children[0];
} else {
*pResult = nullptr;
hr = E_FAIL;
}
CoTaskMemFree(children);
return hr;
}
class TrivialDxcUnsavedFile : IDxcUnsavedFile
{
private:
volatile std::atomic<llvm::sys::cas_flag> m_dwRef;
LPCSTR m_fileName;
LPCSTR m_contents;
unsigned m_length;
public:
TrivialDxcUnsavedFile(LPCSTR fileName, LPCSTR contents)
: m_dwRef(0), m_fileName(fileName), m_contents(contents)
{
m_length = strlen(m_contents);
}
static HRESULT Create(LPCSTR fileName, LPCSTR contents, IDxcUnsavedFile** pResult)
{
CComPtr<TrivialDxcUnsavedFile> pNewValue = new TrivialDxcUnsavedFile(fileName, contents);
return pNewValue.QueryInterface(pResult);
}
ULONG STDMETHODCALLTYPE AddRef() { return (ULONG)++m_dwRef; }
ULONG STDMETHODCALLTYPE Release() {
ULONG result = (ULONG)--m_dwRef;
if (result == 0) delete this;
return result;
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject)
{
if (ppvObject == nullptr) return E_POINTER;
if (IsEqualIID(iid, __uuidof(IUnknown)) ||
IsEqualIID(iid, __uuidof(INoMarshal)) ||
IsEqualIID(iid, __uuidof(IDxcUnsavedFile)))
{
*ppvObject = reinterpret_cast<IDxcUnsavedFile*>(this);
reinterpret_cast<IDxcUnsavedFile*>(this)->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE GetFileName(LPSTR* pFileName)
{
*pFileName = (LPSTR)CoTaskMemAlloc(1 + strlen(m_fileName));
strcpy(*pFileName, m_fileName);
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetContents(LPSTR* pContents)
{
*pContents = (LPSTR)CoTaskMemAlloc(m_length + 1);
memcpy(*pContents, m_contents, m_length + 1);
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetLength(unsigned* pLength)
{
*pLength = m_length;
return S_OK;
}
};
class HlslIntellisenseSupport : public dxc::DxcDllSupport {
public:
HlslIntellisenseSupport() {}
HlslIntellisenseSupport(HlslIntellisenseSupport &&other)
: dxc::DxcDllSupport(std::move(other)) {}
HRESULT CreateIntellisense(_Outptr_ IDxcIntelliSense **pResult) {
return CreateInstance(CLSID_DxcIntelliSense, pResult);
}
};
/// Summary of the results of a clang compilation operation.
class CompilationResult
{
private:
// Keep Intellisense alive.
std::shared_ptr<HlslIntellisenseSupport> IsenseSupport;
/// The top-level Intellisense object.
CComPtr<IDxcIntelliSense> Intellisense;
/// The libclang index for the compilation operation.
CComPtr<IDxcIndex> Index;
/// The number of diagnostic messages emitted.
unsigned NumDiagnostics;
/// The number of diagnostic messages emitted that indicate errors.
unsigned NumErrorDiagnostics;
/// The diagnostic messages emitted.
std::vector<std::string> DiagnosticMessages;
/// The severity of diagnostic messages.
std::vector<DxcDiagnosticSeverity> DiagnosticSeverities;
// Hide the copy constructor.
CompilationResult(const CompilationResult&);
public:
CompilationResult(std::shared_ptr<HlslIntellisenseSupport> support, IDxcIntelliSense* isense, IDxcIndex* index, IDxcTranslationUnit* tu) :
IsenseSupport(support),
Intellisense(isense),
Index(index),
NumErrorDiagnostics(0),
TU(tu)
{
if (tu) {
IFE(tu->GetNumDiagnostics(&NumDiagnostics));
} else {
NumDiagnostics = 0;
}
DxcDiagnosticDisplayOptions diagnosticOptions;
IFE(isense->GetDefaultDiagnosticDisplayOptions(&diagnosticOptions));
for (unsigned i = 0; i < NumDiagnostics; i++) {
CComPtr<IDxcDiagnostic> diagnostic;
IFE(tu->GetDiagnostic(i, &diagnostic));
LPSTR format;
IFE(diagnostic->FormatDiagnostic(diagnosticOptions, &format));
DiagnosticMessages.push_back(std::string(format));
CoTaskMemFree(format);
DxcDiagnosticSeverity severity;
IFE(diagnostic->GetSeverity(&severity));
DiagnosticSeverities.push_back(severity);
if (IsErrorSeverity(severity)) {
NumErrorDiagnostics++;
}
}
assert(NumErrorDiagnostics <= NumDiagnostics && "else counting code in loop is incorrect");
assert(DiagnosticMessages.size() == NumDiagnostics && "else some diagnostics have no message");
assert(DiagnosticSeverities.size() == NumDiagnostics && "else some diagnostics have no severity");
}
CompilationResult(CompilationResult&& other) :
IsenseSupport(std::move(other.IsenseSupport)) {
// Allow move constructor.
Intellisense = other.Intellisense; other.Intellisense = nullptr;
Index = other.Index; other.Index = nullptr;
TU = other.TU; other.TU = nullptr;
NumDiagnostics = other.NumDiagnostics;
NumErrorDiagnostics = other.NumErrorDiagnostics;
DiagnosticMessages = std::move(other.DiagnosticMessages);
DiagnosticSeverities = std::move(other.DiagnosticSeverities);
}
~CompilationResult() { Dispose(); }
/// The translation unit resulting from the compilation.
CComPtr<IDxcTranslationUnit> TU;
static const char *getDefaultFileName() { return "filename.hlsl"; }
static std::shared_ptr<HlslIntellisenseSupport> DefaultHlslSupport;
static std::shared_ptr<HlslIntellisenseSupport> GetHlslSupport() {
if (DefaultHlslSupport.get() != nullptr) {
return DefaultHlslSupport;
}
std::shared_ptr<HlslIntellisenseSupport> result = std::make_shared<HlslIntellisenseSupport>();
IFE(result->Initialize());
return result;
}
static CompilationResult CreateForProgramAndArgs(const char* text, size_t textLen,
_In_count_(commandLineArgsCount) const char* commandLineArgs[],
unsigned commandLineArgsCount,
_In_opt_ DxcTranslationUnitFlags* options = nullptr)
{
std::shared_ptr<HlslIntellisenseSupport> support(GetHlslSupport());
CComPtr<IDxcIntelliSense> isense;
IFE(support->CreateIntellisense(&isense));
CComPtr<IDxcIndex> tuIndex;
CComPtr<IDxcTranslationUnit> tu;
const char *fileName = getDefaultFileName();
if (textLen == 0) textLen = strlen(text);
IFE(isense->CreateIndex(&tuIndex));
CComPtr<IDxcUnsavedFile> unsavedFile;
IFE(TrivialDxcUnsavedFile::Create(fileName, text, &unsavedFile));
DxcTranslationUnitFlags localOptions;
if (options == nullptr)
{
IFE(isense->GetDefaultEditingTUOptions(&localOptions));
}
else
{
localOptions = *options;
}
IFE(tuIndex->ParseTranslationUnit(fileName,
commandLineArgs, commandLineArgsCount,
&(unsavedFile.p), 1, localOptions, &tu));
return CompilationResult(support, isense.p, tuIndex.p, tu.p);
}
static CompilationResult
CreateForProgram(const char *text, size_t textLen,
_In_opt_ DxcTranslationUnitFlags *options = nullptr) {
const char *commandLineArgs[] = {"-c", "-ferror-limit=200"};
unsigned commandLineArgsCount = _countof(commandLineArgs);
return CreateForProgramAndArgs(text, textLen, commandLineArgs,
commandLineArgsCount, options);
}
static CompilationResult CreateForCommandLine(char* arguments, const char* fileName) {
std::shared_ptr<HlslIntellisenseSupport> support(GetHlslSupport());
return CreateForCommandLine(arguments, fileName, support);
}
static CompilationResult CreateForCommandLine(char* arguments, const char* fileName, std::shared_ptr<HlslIntellisenseSupport> support) {
CComPtr<IDxcIntelliSense> isense;
IFE(support->CreateIntellisense(&isense));
CComPtr<IDxcIndex> tuIndex;
CComPtr<IDxcTranslationUnit> tu;
const char* commandLineArgs[32];
unsigned commandLineArgsCount = 0;
char* nextArg = arguments;
// Set a very high number of errors to avoid giving up too early.
commandLineArgs[commandLineArgsCount++] = "-ferror-limit=2000";
// Turn on spell checking for compatibility. This produces error messages
// that suggest corrected spellings.
commandLineArgs[commandLineArgsCount++] = "-fspell-checking";
// Turn off color diagnostics to avoid control characters in diagnostic
// stream.
commandLineArgs[commandLineArgsCount++] = "-fno-color-diagnostics";
IFE(isense->CreateIndex(&tuIndex));
// Split command line arguments by spaces
if (nextArg) {
// skip leading spaces
while (*nextArg == ' ')
nextArg++;
commandLineArgs[commandLineArgsCount++] = nextArg;
while ((*nextArg != '\0')) {
if (*nextArg == ' ') {
*nextArg = 0;
commandLineArgs[commandLineArgsCount++] = nextArg + 1;
}
nextArg++;
}
}
DxcTranslationUnitFlags options;
IFE(isense->GetDefaultEditingTUOptions(&options));
IFE(tuIndex->ParseTranslationUnit(fileName, commandLineArgs,
commandLineArgsCount, nullptr, 0, options,
&tu));
return CompilationResult(support, isense.p, tuIndex.p, tu.p);
}
bool IsTUAvailable() const { return TU != nullptr; }
bool ParseSucceeded() const { return TU != nullptr && NumErrorDiagnostics == 0; }
static bool IsErrorSeverity(DxcDiagnosticSeverity severity)
{
return (severity == DxcDiagnostic_Error || severity == DxcDiagnostic_Fatal);
}
/// Gets a string with all error messages concatenated, one per line.
std::string GetTextForErrors() const {
assert(DiagnosticMessages.size() == NumDiagnostics && "otherwise some diagnostics have no message");
assert(DiagnosticSeverities.size() == NumDiagnostics && "otherwise some diagnostics have no severity");
std::stringstream ostr;
for (size_t i = 0; i < DiagnosticMessages.size(); i++) {
if (IsErrorSeverity(DiagnosticSeverities[i])) {
ostr << DiagnosticMessages[i] << '\n';
}
}
return ostr.str();
}
/// Releases resources, including the translation unit AST.
void Dispose()
{
TU = nullptr;
Index = nullptr;
Intellisense = nullptr;
IsenseSupport = nullptr;
}
private:
#if SUPPORTS_CURSOR_WALK
struct CursorStringData {
std::stringstream &ostr;
std::vector<CXCursor> cursors;
CursorStringData(std::stringstream &the_ostr) : ostr(the_ostr) {}
};
static
CXChildVisitResult AppendCursorStringCallback(
CXCursor cursor, CXCursor parent, CXClientData client_data)
{
CursorStringData* d = (CursorStringData*)client_data;
auto cursorsStart = std::begin(d->cursors);
auto cursorsEnd = std::end(d->cursors);
auto parentLocation = std::find(cursorsStart, cursorsEnd, parent);
assert(parentLocation != cursorsEnd && "otherwise the parent was not visited previously");
AppendCursorString(cursor, parentLocation - cursorsStart, d->ostr);
d->cursors.resize(1 + (parentLocation - cursorsStart));
d->cursors.push_back(cursor);
return CXChildVisit_Recurse;
}
#endif
static
void AppendCursorString(IDxcCursor* cursor, size_t indent, std::stringstream& ostr)
{
if (indent > 0) {
std::streamsize prior = ostr.width();
ostr.width(indent);
ostr << ' ';
ostr.width(prior);
}
CComPtr<IDxcType> type;
DxcCursorKind kind;
cursor->GetKind(&kind);
cursor->GetCursorType(&type);
switch (kind)
{
case DxcCursor_UnexposedDecl: ostr << "UnexposedDecl"; break;
case DxcCursor_StructDecl: ostr << "StructDecl"; break;
case DxcCursor_UnionDecl: ostr << "UnionDecl"; break;
case DxcCursor_ClassDecl: ostr << "ClassDecl"; break;
case DxcCursor_EnumDecl: ostr << "EnumDecl"; break;
case DxcCursor_FieldDecl: ostr << "FieldDecl"; break;
case DxcCursor_EnumConstantDecl: ostr << "EnumConstantDecl"; break;
case DxcCursor_FunctionDecl: ostr << "FunctionDecl"; break;
case DxcCursor_VarDecl: ostr << "VarDecl"; break;
case DxcCursor_ParmDecl: ostr << "ParmDecl"; break;
case DxcCursor_ObjCInterfaceDecl: ostr << "ObjCInterfaceDecl"; break;
case DxcCursor_ObjCCategoryDecl: ostr << "ObjCCategoryDecl"; break;
case DxcCursor_ObjCProtocolDecl: ostr << "ObjCProtocolDecl"; break;
case DxcCursor_ObjCPropertyDecl: ostr << "ObjCPropertyDecl"; break;
case DxcCursor_ObjCIvarDecl: ostr << "ObjCIvarDecl"; break;
case DxcCursor_ObjCInstanceMethodDecl: ostr << "ObjCInstanceMethodDecl"; break;
case DxcCursor_ObjCClassMethodDecl: ostr << "ObjCClassMethodDecl"; break;
case DxcCursor_ObjCImplementationDecl: ostr << "ObjCImplementationDecl"; break;
case DxcCursor_ObjCCategoryImplDecl: ostr << "ObjCCategoryImplDecl"; break;
case DxcCursor_TypedefDecl: ostr << "TypedefDecl"; break;
case DxcCursor_CXXMethod: ostr << "CXXMethod"; break;
case DxcCursor_Namespace: ostr << "Namespace"; break;
case DxcCursor_LinkageSpec: ostr << "LinkageSpec"; break;
case DxcCursor_Constructor: ostr << "Constructor"; break;
case DxcCursor_Destructor: ostr << "Destructor"; break;
case DxcCursor_ConversionFunction: ostr << "ConversionFunction"; break;
case DxcCursor_TemplateTypeParameter: ostr << "TemplateTypeParameter"; break;
case DxcCursor_NonTypeTemplateParameter: ostr << "NonTypeTemplateParameter"; break;
case DxcCursor_TemplateTemplateParameter: ostr << "TemplateTemplateParameter"; break;
case DxcCursor_FunctionTemplate: ostr << "FunctionTemplate"; break;
case DxcCursor_ClassTemplate: ostr << "ClassTemplate"; break;
case DxcCursor_ClassTemplatePartialSpecialization: ostr << "ClassTemplatePartialSpecialization"; break;
case DxcCursor_NamespaceAlias: ostr << "NamespaceAlias"; break;
case DxcCursor_UsingDirective: ostr << "UsingDirective"; break;
case DxcCursor_UsingDeclaration: ostr << "UsingDeclaration"; break;
case DxcCursor_TypeAliasDecl: ostr << "TypeAliasDecl"; break;
case DxcCursor_ObjCSynthesizeDecl: ostr << "ObjCSynthesizeDecl"; break;
case DxcCursor_ObjCDynamicDecl: ostr << "ObjCDynamicDecl"; break;
case DxcCursor_CXXAccessSpecifier: ostr << "CXXAccessSpecifier"; break;
case DxcCursor_ObjCSuperClassRef: ostr << "ObjCSuperClassRef"; break;
case DxcCursor_ObjCProtocolRef: ostr << "ObjCProtocolRef"; break;
case DxcCursor_ObjCClassRef: ostr << "ObjCClassRef"; break;
case DxcCursor_TypeRef: ostr << "TypeRef"; break;
case DxcCursor_CXXBaseSpecifier: ostr << "CXXBaseSpecifier"; break;
case DxcCursor_TemplateRef: ostr << "TemplateRef"; break;
case DxcCursor_NamespaceRef: ostr << "NamespaceRef"; break;
case DxcCursor_MemberRef: ostr << "MemberRef"; break;
case DxcCursor_LabelRef: ostr << "LabelRef"; break;
case DxcCursor_OverloadedDeclRef: ostr << "OverloadedDeclRef"; break;
case DxcCursor_VariableRef: ostr << "VariableRef"; break;
case DxcCursor_InvalidFile: ostr << "InvalidFile"; break;
case DxcCursor_NoDeclFound: ostr << "NoDeclFound"; break;
case DxcCursor_NotImplemented: ostr << "NotImplemented"; break;
case DxcCursor_InvalidCode: ostr << "InvalidCode"; break;
case DxcCursor_UnexposedExpr: ostr << "UnexposedExpr"; break;
case DxcCursor_DeclRefExpr: ostr << "DeclRefExpr"; break;
case DxcCursor_MemberRefExpr: ostr << "MemberRefExpr"; break;
case DxcCursor_CallExpr: ostr << "CallExpr"; break;
case DxcCursor_ObjCMessageExpr: ostr << "ObjCMessageExpr"; break;
case DxcCursor_BlockExpr: ostr << "BlockExpr"; break;
case DxcCursor_IntegerLiteral: ostr << "IntegerLiteral"; break;
case DxcCursor_FloatingLiteral: ostr << "FloatingLiteral"; break;
case DxcCursor_ImaginaryLiteral: ostr << "ImaginaryLiteral"; break;
case DxcCursor_StringLiteral: ostr << "StringLiteral"; break;
case DxcCursor_CharacterLiteral: ostr << "CharacterLiteral"; break;
case DxcCursor_ParenExpr: ostr << "ParenExpr"; break;
case DxcCursor_UnaryOperator: ostr << "UnaryOperator"; break;
case DxcCursor_ArraySubscriptExpr: ostr << "ArraySubscriptExpr"; break;
case DxcCursor_BinaryOperator: ostr << "BinaryOperator"; break;
case DxcCursor_CompoundAssignOperator: ostr << "CompoundAssignOperator"; break;
case DxcCursor_ConditionalOperator: ostr << "ConditionalOperator"; break;
case DxcCursor_CStyleCastExpr: ostr << "CStyleCastExpr"; break;
case DxcCursor_CompoundLiteralExpr: ostr << "CompoundLiteralExpr"; break;
case DxcCursor_InitListExpr: ostr << "InitListExpr"; break;
case DxcCursor_AddrLabelExpr: ostr << "AddrLabelExpr"; break;
case DxcCursor_StmtExpr: ostr << "StmtExpr"; break;
case DxcCursor_GenericSelectionExpr: ostr << "GenericSelectionExpr"; break;
case DxcCursor_GNUNullExpr: ostr << "GNUNullExpr"; break;
case DxcCursor_CXXStaticCastExpr: ostr << "CXXStaticCastExpr"; break;
case DxcCursor_CXXDynamicCastExpr: ostr << "CXXDynamicCastExpr"; break;
case DxcCursor_CXXReinterpretCastExpr: ostr << "CXXReinterpretCastExpr"; break;
case DxcCursor_CXXConstCastExpr: ostr << "CXXConstCastExpr"; break;
case DxcCursor_CXXFunctionalCastExpr: ostr << "CXXFunctionalCastExpr"; break;
case DxcCursor_CXXTypeidExpr: ostr << "CXXTypeidExpr"; break;
case DxcCursor_CXXBoolLiteralExpr: ostr << "CXXBoolLiteralExpr"; break;
case DxcCursor_CXXNullPtrLiteralExpr: ostr << "CXXNullPtrLiteralExpr"; break;
case DxcCursor_CXXThisExpr: ostr << "CXXThisExpr"; break;
case DxcCursor_CXXThrowExpr: ostr << "CXXThrowExpr"; break;
case DxcCursor_CXXNewExpr: ostr << "CXXNewExpr"; break;
case DxcCursor_CXXDeleteExpr: ostr << "CXXDeleteExpr"; break;
case DxcCursor_UnaryExpr: ostr << "UnaryExpr"; break;
case DxcCursor_ObjCStringLiteral: ostr << "ObjCStringLiteral"; break;
case DxcCursor_ObjCEncodeExpr: ostr << "ObjCEncodeExpr"; break;
case DxcCursor_ObjCSelectorExpr: ostr << "ObjCSelectorExpr"; break;
case DxcCursor_ObjCProtocolExpr: ostr << "ObjCProtocolExpr"; break;
case DxcCursor_ObjCBridgedCastExpr: ostr << "ObjCBridgedCastExpr"; break;
case DxcCursor_PackExpansionExpr: ostr << "PackExpansionExpr"; break;
case DxcCursor_SizeOfPackExpr: ostr << "SizeOfPackExpr"; break;
case DxcCursor_LambdaExpr: ostr << "LambdaExpr"; break;
case DxcCursor_ObjCBoolLiteralExpr: ostr << "ObjCBoolLiteralExpr"; break;
case DxcCursor_ObjCSelfExpr: ostr << "ObjCSelfExpr"; break;
case DxcCursor_UnexposedStmt: ostr << "UnexposedStmt"; break;
case DxcCursor_LabelStmt: ostr << "LabelStmt"; break;
case DxcCursor_CompoundStmt: ostr << "CompoundStmt"; break;
case DxcCursor_CaseStmt: ostr << "CaseStmt"; break;
case DxcCursor_DefaultStmt: ostr << "DefaultStmt"; break;
case DxcCursor_IfStmt: ostr << "IfStmt"; break;
case DxcCursor_SwitchStmt: ostr << "SwitchStmt"; break;
case DxcCursor_WhileStmt: ostr << "WhileStmt"; break;
case DxcCursor_DoStmt: ostr << "DoStmt"; break;
case DxcCursor_ForStmt: ostr << "ForStmt"; break;
case DxcCursor_GotoStmt: ostr << "GotoStmt"; break;
case DxcCursor_IndirectGotoStmt: ostr << "IndirectGotoStmt"; break;
case DxcCursor_ContinueStmt: ostr << "ContinueStmt"; break;
case DxcCursor_BreakStmt: ostr << "BreakStmt"; break;
case DxcCursor_ReturnStmt: ostr << "ReturnStmt"; break;
case DxcCursor_GCCAsmStmt: ostr << "GCCAsmStmt"; break;
case DxcCursor_ObjCAtTryStmt: ostr << "ObjCAtTryStmt"; break;
case DxcCursor_ObjCAtCatchStmt: ostr << "ObjCAtCatchStmt"; break;
case DxcCursor_ObjCAtFinallyStmt: ostr << "ObjCAtFinallyStmt"; break;
case DxcCursor_ObjCAtThrowStmt: ostr << "ObjCAtThrowStmt"; break;
case DxcCursor_ObjCAtSynchronizedStmt: ostr << "ObjCAtSynchronizedStmt"; break;
case DxcCursor_ObjCAutoreleasePoolStmt: ostr << "ObjCAutoreleasePoolStmt"; break;
case DxcCursor_ObjCForCollectionStmt: ostr << "ObjCForCollectionStmt"; break;
case DxcCursor_CXXCatchStmt: ostr << "CXXCatchStmt"; break;
case DxcCursor_CXXTryStmt: ostr << "CXXTryStmt"; break;
case DxcCursor_CXXForRangeStmt: ostr << "CXXForRangeStmt"; break;
case DxcCursor_SEHTryStmt: ostr << "SEHTryStmt"; break;
case DxcCursor_SEHExceptStmt: ostr << "SEHExceptStmt"; break;
case DxcCursor_SEHFinallyStmt: ostr << "SEHFinallyStmt"; break;
case DxcCursor_MSAsmStmt: ostr << "MSAsmStmt"; break;
case DxcCursor_NullStmt: ostr << "NullStmt"; break;
case DxcCursor_DeclStmt: ostr << "DeclStmt"; break;
case DxcCursor_OMPParallelDirective: ostr << "OMPParallelDirective"; break;
case DxcCursor_TranslationUnit: ostr << "TranslationUnit"; break;
case DxcCursor_UnexposedAttr: ostr << "UnexposedAttr"; break;
#if 0
CXCursor_IBActionAttr = 401,
CXCursor_IBOutletAttr = 402,
CXCursor_IBOutletCollectionAttr = 403,
CXCursor_CXXFinalAttr = 404,
CXCursor_CXXOverrideAttr = 405,
CXCursor_AnnotateAttr = 406,
CXCursor_AsmLabelAttr = 407,
CXCursor_PackedAttr = 408,
/* Preprocessing */
CXCursor_PreprocessingDirective = 500,
CXCursor_MacroDefinition = 501,
CXCursor_MacroExpansion = 502,
CXCursor_InclusionDirective = 503,
case CXCursor_FunctionDecl:
break;
case CXCursor_ClassDecl:
ostr << "class decl";
break;
case CXCursor_TranslationUnit:
ostr << "translation unit";
break;
#endif
default:
ostr << "unknown/unhandled cursor kind " << kind;
break;
}
DxcTypeKind typeKind;
if (type != nullptr && SUCCEEDED(type->GetKind(&typeKind)) &&
typeKind != DxcTypeKind_Invalid) {
LPSTR name;
type->GetSpelling(&name);
ostr << " [type " << name << "]";
CoTaskMemFree(name);
}
ostr << '\n';
// Recurse.
IDxcCursor** children = nullptr;
unsigned childrenCount;
cursor->GetChildren(0, 64, &childrenCount, &children);
for (unsigned i = 0; i < childrenCount; i++) {
AppendCursorString(children[i], indent + 1, ostr);
children[i]->Release();
}
CoTaskMemFree(children);
}
public:
std::string BuildASTString() {
if (TU == nullptr) {
return "<failed to build - TU is null>";
}
CComPtr<IDxcCursor> cursor;
std::stringstream ostr;
this->TU->GetCursor(&cursor);
AppendCursorString(cursor, 0, ostr);
return ostr.str();
}
};