feat(lint): naming reads the AST, deleting the scope heuristic

The rule was 125 lines: four std::regex, a hand-rolled {/} scope stack, a
cumulative paren-depth counter so a wrapped parameter list would not look like
a declaration, a 40-entry keyword denylist, and a "function-shaped line" guess
whose own comment conceded it was heuristic. Storage class came from
lineStr.contains("static "). It is now ~55 lines that ask clang what kind of
declaration each thing is and what encloses it.

The three regressions the old version carried special cases for — a call with
an inline lambda argument, a bare statement call, a one-liner method — need no
handling at all, because a call is not a declaration. Their tests pass
unchanged.

On this repository the exact version found 42 violations the heuristic had
never been able to see, all real:

  - 37 members of the libclang function-pointer table added two commits ago
    were PascalCase. The old varDecl regex could not match a declaration whose
    type is decltype(&f), so they were silently skipped. Renamed to camelCase,
    which mirrors clang_createIndex -> createIndex more closely anyway.
  - Crafter.Build-Shader.cpp had a snake_case local, file_name_list, invisible
    to the heuristic for the same reason (it declares a const char* array).
  - Four extern "C" declarations of libc functions in tests were reported as
    badly-named functions. Those are named by the C library, so C language
    linkage is now an exemption — the same principled test no-char-pointer
    uses, rather than another denylist entry.

New tests cover what the line-based version structurally could not reach: a
signature wrapped over several lines, `static` on its own line above the
declaration it applies to, and a member versus a local inside a method.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-07-30 23:53:26 +02:00
commit d55657b7ce
4 changed files with 227 additions and 255 deletions

View file

@ -50,44 +50,44 @@ namespace {
LibHandle handle = nullptr;
std::string error; // non-empty exactly when handle is null
decltype(&clang_createIndex) CreateIndex = nullptr;
decltype(&clang_disposeIndex) DisposeIndex = nullptr;
decltype(&clang_parseTranslationUnit) ParseTranslationUnit = nullptr;
decltype(&clang_disposeTranslationUnit) DisposeTranslationUnit = nullptr;
decltype(&clang_getFile) GetFile = nullptr;
decltype(&clang_getLocationForOffset) GetLocationForOffset = nullptr;
decltype(&clang_getRange) GetRange = nullptr;
decltype(&clang_getRangeStart) GetRangeStart = nullptr;
decltype(&clang_getRangeEnd) GetRangeEnd = nullptr;
decltype(&clang_getFileLocation) GetFileLocation = nullptr;
decltype(&clang_tokenize) Tokenize = nullptr;
decltype(&clang_disposeTokens) DisposeTokens = nullptr;
decltype(&clang_getTokenKind) GetTokenKind = nullptr;
decltype(&clang_getTokenExtent) GetTokenExtent = nullptr;
decltype(&clang_createIndex) createIndex = nullptr;
decltype(&clang_disposeIndex) disposeIndex = nullptr;
decltype(&clang_parseTranslationUnit) parseTranslationUnit = nullptr;
decltype(&clang_disposeTranslationUnit) disposeTranslationUnit = nullptr;
decltype(&clang_getFile) getFile = nullptr;
decltype(&clang_getLocationForOffset) getLocationForOffset = nullptr;
decltype(&clang_getRange) getRange = nullptr;
decltype(&clang_getRangeStart) getRangeStart = nullptr;
decltype(&clang_getRangeEnd) getRangeEnd = nullptr;
decltype(&clang_getFileLocation) getFileLocation = nullptr;
decltype(&clang_tokenize) tokenize = nullptr;
decltype(&clang_disposeTokens) disposeTokens = nullptr;
decltype(&clang_getTokenKind) getTokenKind = nullptr;
decltype(&clang_getTokenExtent) getTokenExtent = nullptr;
// AST layer.
decltype(&clang_getTranslationUnitCursor) GetTranslationUnitCursor = nullptr;
decltype(&clang_visitChildren) VisitChildren = nullptr;
decltype(&clang_getCursorKind) GetCursorKind = nullptr;
decltype(&clang_getCursorSpelling) GetCursorSpelling = nullptr;
decltype(&clang_getCursorType) GetCursorType = nullptr;
decltype(&clang_getTypeSpelling) GetTypeSpelling = nullptr;
decltype(&clang_getCursorLocation) GetCursorLocation = nullptr;
decltype(&clang_getCursorExtent) GetCursorExtent = nullptr;
decltype(&clang_getCursorReferenced) GetCursorReferenced = nullptr;
decltype(&clang_Cursor_getStorageClass) GetStorageClass = nullptr;
decltype(&clang_EnumDecl_isScoped) EnumDeclIsScoped = nullptr;
decltype(&clang_isCursorDefinition) IsCursorDefinition = nullptr;
decltype(&clang_Location_isFromMainFile) LocationIsFromMainFile = nullptr;
decltype(&clang_getNumDiagnostics) GetNumDiagnostics = nullptr;
decltype(&clang_getDiagnostic) GetDiagnostic = nullptr;
decltype(&clang_getDiagnosticSeverity) GetDiagnosticSeverity = nullptr;
decltype(&clang_getDiagnosticSpelling) GetDiagnosticSpelling = nullptr;
decltype(&clang_disposeDiagnostic) DisposeDiagnostic = nullptr;
decltype(&clang_getCString) GetCString = nullptr;
decltype(&clang_disposeString) DisposeString = nullptr;
decltype(&clang_getFileName) GetFileName = nullptr;
decltype(&clang_Cursor_isNull) CursorIsNull = nullptr;
decltype(&clang_getResultType) GetResultType = nullptr;
decltype(&clang_getTranslationUnitCursor) getTranslationUnitCursor = nullptr;
decltype(&clang_visitChildren) visitChildren = nullptr;
decltype(&clang_getCursorKind) getCursorKind = nullptr;
decltype(&clang_getCursorSpelling) getCursorSpelling = nullptr;
decltype(&clang_getCursorType) getCursorType = nullptr;
decltype(&clang_getTypeSpelling) getTypeSpelling = nullptr;
decltype(&clang_getCursorLocation) getCursorLocation = nullptr;
decltype(&clang_getCursorExtent) getCursorExtent = nullptr;
decltype(&clang_getCursorReferenced) getCursorReferenced = nullptr;
decltype(&clang_Cursor_getStorageClass) getStorageClass = nullptr;
decltype(&clang_EnumDecl_isScoped) enumDeclIsScoped = nullptr;
decltype(&clang_isCursorDefinition) isCursorDefinition = nullptr;
decltype(&clang_Location_isFromMainFile) locationIsFromMainFile = nullptr;
decltype(&clang_getNumDiagnostics) getNumDiagnostics = nullptr;
decltype(&clang_getDiagnostic) getDiagnostic = nullptr;
decltype(&clang_getDiagnosticSeverity) getDiagnosticSeverity = nullptr;
decltype(&clang_getDiagnosticSpelling) getDiagnosticSpelling = nullptr;
decltype(&clang_disposeDiagnostic) disposeDiagnostic = nullptr;
decltype(&clang_getCString) getCString = nullptr;
decltype(&clang_disposeString) disposeString = nullptr;
decltype(&clang_getFileName) getFileName = nullptr;
decltype(&clang_Cursor_isNull) cursorIsNull = nullptr;
decltype(&clang_getResultType) getResultType = nullptr;
};
LibClang LoadLibClang() {
@ -129,43 +129,43 @@ namespace {
slot = reinterpret_cast<std::remove_reference_t<decltype(slot)>>(LibrarySymbol(lib.handle, name));
if (!slot) missing.push_back(name);
};
bind(lib.CreateIndex, "clang_createIndex");
bind(lib.DisposeIndex, "clang_disposeIndex");
bind(lib.ParseTranslationUnit, "clang_parseTranslationUnit");
bind(lib.DisposeTranslationUnit, "clang_disposeTranslationUnit");
bind(lib.GetFile, "clang_getFile");
bind(lib.GetLocationForOffset, "clang_getLocationForOffset");
bind(lib.GetRange, "clang_getRange");
bind(lib.GetRangeStart, "clang_getRangeStart");
bind(lib.GetRangeEnd, "clang_getRangeEnd");
bind(lib.GetFileLocation, "clang_getFileLocation");
bind(lib.Tokenize, "clang_tokenize");
bind(lib.DisposeTokens, "clang_disposeTokens");
bind(lib.GetTokenKind, "clang_getTokenKind");
bind(lib.GetTokenExtent, "clang_getTokenExtent");
bind(lib.GetTranslationUnitCursor, "clang_getTranslationUnitCursor");
bind(lib.VisitChildren, "clang_visitChildren");
bind(lib.GetCursorKind, "clang_getCursorKind");
bind(lib.GetCursorSpelling, "clang_getCursorSpelling");
bind(lib.GetCursorType, "clang_getCursorType");
bind(lib.GetTypeSpelling, "clang_getTypeSpelling");
bind(lib.GetCursorLocation, "clang_getCursorLocation");
bind(lib.GetCursorExtent, "clang_getCursorExtent");
bind(lib.GetCursorReferenced, "clang_getCursorReferenced");
bind(lib.GetStorageClass, "clang_Cursor_getStorageClass");
bind(lib.EnumDeclIsScoped, "clang_EnumDecl_isScoped");
bind(lib.IsCursorDefinition, "clang_isCursorDefinition");
bind(lib.LocationIsFromMainFile, "clang_Location_isFromMainFile");
bind(lib.GetNumDiagnostics, "clang_getNumDiagnostics");
bind(lib.GetDiagnostic, "clang_getDiagnostic");
bind(lib.GetDiagnosticSeverity, "clang_getDiagnosticSeverity");
bind(lib.GetDiagnosticSpelling, "clang_getDiagnosticSpelling");
bind(lib.DisposeDiagnostic, "clang_disposeDiagnostic");
bind(lib.GetCString, "clang_getCString");
bind(lib.DisposeString, "clang_disposeString");
bind(lib.GetFileName, "clang_getFileName");
bind(lib.CursorIsNull, "clang_Cursor_isNull");
bind(lib.GetResultType, "clang_getResultType");
bind(lib.createIndex, "clang_createIndex");
bind(lib.disposeIndex, "clang_disposeIndex");
bind(lib.parseTranslationUnit, "clang_parseTranslationUnit");
bind(lib.disposeTranslationUnit, "clang_disposeTranslationUnit");
bind(lib.getFile, "clang_getFile");
bind(lib.getLocationForOffset, "clang_getLocationForOffset");
bind(lib.getRange, "clang_getRange");
bind(lib.getRangeStart, "clang_getRangeStart");
bind(lib.getRangeEnd, "clang_getRangeEnd");
bind(lib.getFileLocation, "clang_getFileLocation");
bind(lib.tokenize, "clang_tokenize");
bind(lib.disposeTokens, "clang_disposeTokens");
bind(lib.getTokenKind, "clang_getTokenKind");
bind(lib.getTokenExtent, "clang_getTokenExtent");
bind(lib.getTranslationUnitCursor, "clang_getTranslationUnitCursor");
bind(lib.visitChildren, "clang_visitChildren");
bind(lib.getCursorKind, "clang_getCursorKind");
bind(lib.getCursorSpelling, "clang_getCursorSpelling");
bind(lib.getCursorType, "clang_getCursorType");
bind(lib.getTypeSpelling, "clang_getTypeSpelling");
bind(lib.getCursorLocation, "clang_getCursorLocation");
bind(lib.getCursorExtent, "clang_getCursorExtent");
bind(lib.getCursorReferenced, "clang_getCursorReferenced");
bind(lib.getStorageClass, "clang_Cursor_getStorageClass");
bind(lib.enumDeclIsScoped, "clang_EnumDecl_isScoped");
bind(lib.isCursorDefinition, "clang_isCursorDefinition");
bind(lib.locationIsFromMainFile, "clang_Location_isFromMainFile");
bind(lib.getNumDiagnostics, "clang_getNumDiagnostics");
bind(lib.getDiagnostic, "clang_getDiagnostic");
bind(lib.getDiagnosticSeverity, "clang_getDiagnosticSeverity");
bind(lib.getDiagnosticSpelling, "clang_getDiagnosticSpelling");
bind(lib.disposeDiagnostic, "clang_disposeDiagnostic");
bind(lib.getCString, "clang_getCString");
bind(lib.disposeString, "clang_disposeString");
bind(lib.getFileName, "clang_getFileName");
bind(lib.cursorIsNull, "clang_Cursor_isNull");
bind(lib.getResultType, "clang_getResultType");
if (!missing.empty()) {
lib.handle = nullptr;
lib.error = std::format("loaded {} but it is missing {}", candidates.front(), join(missing));
@ -229,36 +229,36 @@ namespace {
unsaved.Contents = content.data();
unsaved.Length = static_cast<std::uint32_t>(content.size());
CXIndex index = lc.CreateIndex(0, 0);
CXIndex index = lc.createIndex(0, 0);
if (!index) return {};
CXTranslationUnit tu = lc.ParseTranslationUnit(index, path.c_str(), args.data(), static_cast<std::int32_t>(args.size()), &unsaved, 1, CXTranslationUnit_SingleFileParse | CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_KeepGoing);
CXTranslationUnit tu = lc.parseTranslationUnit(index, path.c_str(), args.data(), static_cast<std::int32_t>(args.size()), &unsaved, 1, CXTranslationUnit_SingleFileParse | CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_KeepGoing);
if (!tu) {
lc.DisposeIndex(index);
lc.disposeIndex(index);
return {};
}
std::vector<LintToken> tokens;
if (CXFile cxFile = lc.GetFile(tu, path.c_str())) {
CXSourceRange whole = lc.GetRange(lc.GetLocationForOffset(tu, cxFile, 0), lc.GetLocationForOffset(tu, cxFile, static_cast<std::uint32_t>(content.size())));
if (CXFile cxFile = lc.getFile(tu, path.c_str())) {
CXSourceRange whole = lc.getRange(lc.getLocationForOffset(tu, cxFile, 0), lc.getLocationForOffset(tu, cxFile, static_cast<std::uint32_t>(content.size())));
CXToken* raw = nullptr;
std::uint32_t count = 0;
lc.Tokenize(tu, whole, &raw, &count);
lc.tokenize(tu, whole, &raw, &count);
tokens.reserve(count);
for (std::uint32_t i = 0; i < count; ++i) {
CXSourceRange extent = lc.GetTokenExtent(tu, raw[i]);
CXSourceRange extent = lc.getTokenExtent(tu, raw[i]);
std::uint32_t line = 0;
std::uint32_t column = 0;
std::uint32_t begin = 0;
std::uint32_t end = 0;
lc.GetFileLocation(lc.GetRangeStart(extent), nullptr, &line, &column, &begin);
lc.GetFileLocation(lc.GetRangeEnd(extent), nullptr, nullptr, nullptr, &end);
lc.getFileLocation(lc.getRangeStart(extent), nullptr, &line, &column, &begin);
lc.getFileLocation(lc.getRangeEnd(extent), nullptr, nullptr, nullptr, &end);
if (end < begin || begin > content.size()) continue;
tokens.push_back({MapTokenKind(lc.GetTokenKind(raw[i])), begin, std::min<std::size_t>(end - begin, content.size() - begin), line, column});
tokens.push_back({MapTokenKind(lc.getTokenKind(raw[i])), begin, std::min<std::size_t>(end - begin, content.size() - begin), line, column});
}
if (raw) lc.DisposeTokens(tu, raw, count);
if (raw) lc.disposeTokens(tu, raw, count);
}
lc.DisposeTranslationUnit(tu);
lc.DisposeIndex(index);
lc.disposeTranslationUnit(tu);
lc.disposeIndex(index);
return tokens;
}
@ -269,9 +269,9 @@ namespace {
// works this out for itself now: the initialiser resolves to a
// declaration in clang-c/, outside the project, so the declaration is
// flagged as foreign API and exempt. No suppression comment needed.
const char* raw = lc.GetCString(s);
const char* raw = lc.getCString(s);
std::string out = raw ? raw : "";
lc.DisposeString(s);
lc.disposeString(s);
return out;
}
@ -386,17 +386,17 @@ namespace {
// from where the declaration actually lives.
bool ResolvesOutsideProject(const LibClang& lc, CXCursor cursor, const fs::path& projectRoot) {
if (projectRoot.empty()) return false;
CXCursor target = lc.GetCursorReferenced(cursor);
if (lc.CursorIsNull(target)) return false;
CXSourceLocation location = lc.GetCursorLocation(target);
if (lc.LocationIsFromMainFile(location)) return false;
CXCursor target = lc.getCursorReferenced(cursor);
if (lc.cursorIsNull(target)) return false;
CXSourceLocation location = lc.getCursorLocation(target);
if (lc.locationIsFromMainFile(location)) return false;
CXFile file = nullptr;
std::uint32_t line = 0;
std::uint32_t column = 0;
std::uint32_t offset = 0;
lc.GetFileLocation(location, &file, &line, &column, &offset);
lc.getFileLocation(location, &file, &line, &column, &offset);
if (!file) return false;
std::string path = TakeString(lc, lc.GetFileName(file));
std::string path = TakeString(lc, lc.getFileName(file));
if (path.empty()) return false;
return !PathInsideRoot(fs::path(path), projectRoot);
}
@ -404,13 +404,13 @@ namespace {
CXChildVisitResult VisitDecl(CXCursor cursor, CXCursor, CXClientData data) {
DeclWalk& walk = *static_cast<DeclWalk*>(data);
const LibClang& lc = *walk.lc;
CXSourceLocation location = lc.GetCursorLocation(cursor);
CXSourceLocation location = lc.getCursorLocation(cursor);
// Every declaration the imported modules bring in arrives here too —
// an unfiltered visit of one interface unit walks ~495,000 cursors from
// std alone. Prune before doing any work.
if (!lc.LocationIsFromMainFile(location)) return CXChildVisit_Continue;
if (!lc.locationIsFromMainFile(location)) return CXChildVisit_Continue;
CXCursorKind kind = lc.GetCursorKind(cursor);
CXCursorKind kind = lc.getCursorKind(cursor);
LintDeclKind mapped = MapCursorKind(kind);
if (mapped == LintDeclKind::Other) {
// A foreign reference inside a VARIABLE, FIELD or PARAMETER is an
@ -430,51 +430,51 @@ namespace {
// enclosing-declaration stack stays accurate: the callback is never
// told when a subtree ends.
if (kind == CXCursor_LinkageSpec) {
CXSourceRange extent = lc.GetCursorExtent(cursor);
CXSourceRange extent = lc.getCursorExtent(cursor);
std::uint32_t specBegin = 0;
std::uint32_t specEnd = 0;
lc.GetFileLocation(lc.GetRangeStart(extent), nullptr, nullptr, nullptr, &specBegin);
lc.GetFileLocation(lc.GetRangeEnd(extent), nullptr, nullptr, nullptr, &specEnd);
lc.getFileLocation(lc.getRangeStart(extent), nullptr, nullptr, nullptr, &specBegin);
lc.getFileLocation(lc.getRangeEnd(extent), nullptr, nullptr, nullptr, &specEnd);
std::string_view text;
if (specBegin < walk.content->size()) {
text = std::string_view(walk.content->data() + specBegin, std::min<std::size_t>(specEnd - specBegin, walk.content->size() - specBegin));
}
bool isC = IsExternCLinkage(text);
if (isC) ++walk.externCDepth;
lc.VisitChildren(cursor, &VisitDecl, &walk);
lc.visitChildren(cursor, &VisitDecl, &walk);
if (isC) --walk.externCDepth;
return CXChildVisit_Continue;
}
lc.VisitChildren(cursor, &VisitDecl, &walk);
lc.visitChildren(cursor, &VisitDecl, &walk);
return CXChildVisit_Continue;
}
LintDecl decl;
decl.kind = mapped;
decl.name = TakeString(lc, lc.GetCursorSpelling(cursor));
decl.name = TakeString(lc, lc.getCursorSpelling(cursor));
// For anything callable, `type` is the RESULT type rather than the
// whole function type: the parameters arrive as their own Parameter
// declarations, so spelling them here too would make every rule
// reading `type` report each one twice.
bool callable = mapped == LintDeclKind::Function || mapped == LintDeclKind::Method;
decl.type = TakeString(lc, lc.GetTypeSpelling(callable ? lc.GetResultType(lc.GetCursorType(cursor)) : lc.GetCursorType(cursor)));
decl.type = TakeString(lc, lc.getTypeSpelling(callable ? lc.getResultType(lc.getCursorType(cursor)) : lc.getCursorType(cursor)));
CXFile nameFile = nullptr;
std::uint32_t nameLine = 0;
std::uint32_t nameColumn = 0;
std::uint32_t nameOffset = 0;
lc.GetFileLocation(location, &nameFile, &nameLine, &nameColumn, &nameOffset);
lc.getFileLocation(location, &nameFile, &nameLine, &nameColumn, &nameOffset);
decl.line = nameLine;
decl.column = nameColumn;
CXSourceRange extent = lc.GetCursorExtent(cursor);
CXSourceRange extent = lc.getCursorExtent(cursor);
std::uint32_t begin = 0;
std::uint32_t end = 0;
lc.GetFileLocation(lc.GetRangeStart(extent), nullptr, nullptr, nullptr, &begin);
lc.GetFileLocation(lc.GetRangeEnd(extent), nullptr, nullptr, nullptr, &end);
lc.getFileLocation(lc.getRangeStart(extent), nullptr, nullptr, nullptr, &begin);
lc.getFileLocation(lc.getRangeEnd(extent), nullptr, nullptr, nullptr, &end);
decl.begin = begin;
decl.end = std::min<std::size_t>(end, walk.content->size());
decl.isDefinition = lc.IsCursorDefinition(cursor) != 0;
decl.isStatic = lc.GetStorageClass(cursor) == CX_SC_Static;
decl.isScopedEnum = mapped == LintDeclKind::Enum && lc.EnumDeclIsScoped(cursor) != 0;
decl.isDefinition = lc.isCursorDefinition(cursor) != 0;
decl.isStatic = lc.getStorageClass(cursor) == CX_SC_Static;
decl.isScopedEnum = mapped == LintDeclKind::Enum && lc.enumDeclIsScoped(cursor) != 0;
// Inside an extern "C" block, where a C API's spelling is not ours to
// modernise. NOT clang_getCursorLanguage: its default answer for a
// plain function, variable or parameter is CXLanguage_C even in a C++
@ -492,7 +492,7 @@ namespace {
walk.out->push_back(std::move(decl));
walk.stack.push_back(walk.out->size() - 1);
lc.VisitChildren(cursor, &VisitDecl, &walk);
lc.visitChildren(cursor, &VisitDecl, &walk);
walk.stack.pop_back();
return CXChildVisit_Continue;
}
@ -504,7 +504,7 @@ namespace {
walk.content = &content;
walk.projectRoot = &projectRoot;
walk.out = &decls;
lc.VisitChildren(lc.GetTranslationUnitCursor(tu), &VisitDecl, &walk);
lc.visitChildren(lc.getTranslationUnitCursor(tu), &VisitDecl, &walk);
// A declaration on an interop boundary makes its parameters and fields
// interop too — the exemption has to cover the whole signature, not
// just the node that happened to name the foreign entity.
@ -579,34 +579,34 @@ namespace {
unsaved.Contents = buffer.data();
unsaved.Length = static_cast<std::uint32_t>(buffer.size());
CXIndex index = lc.CreateIndex(0, 0);
CXIndex index = lc.createIndex(0, 0);
if (!index) {
result.error = "clang_createIndex failed";
return result;
}
CXTranslationUnit tu = lc.ParseTranslationUnit(index, path.c_str(), argv.data(), static_cast<std::int32_t>(argv.size()), &unsaved, 1, CXTranslationUnit_None);
CXTranslationUnit tu = lc.parseTranslationUnit(index, path.c_str(), argv.data(), static_cast<std::int32_t>(argv.size()), &unsaved, 1, CXTranslationUnit_None);
if (!tu) {
lc.DisposeIndex(index);
lc.disposeIndex(index);
result.error = "clang could not create a translation unit";
return result;
}
std::string fatal;
std::uint32_t diagnostics = lc.GetNumDiagnostics(tu);
std::uint32_t diagnostics = lc.getNumDiagnostics(tu);
for (std::uint32_t i = 0; i < diagnostics && fatal.empty(); ++i) {
CXDiagnostic diagnostic = lc.GetDiagnostic(tu, i);
if (lc.GetDiagnosticSeverity(diagnostic) == CXDiagnostic_Fatal) {
fatal = TakeString(lc, lc.GetDiagnosticSpelling(diagnostic));
CXDiagnostic diagnostic = lc.getDiagnostic(tu, i);
if (lc.getDiagnosticSeverity(diagnostic) == CXDiagnostic_Fatal) {
fatal = TakeString(lc, lc.getDiagnosticSpelling(diagnostic));
}
lc.DisposeDiagnostic(diagnostic);
lc.disposeDiagnostic(diagnostic);
}
if (fatal.empty()) {
result.decls = WalkDecls(lc, tu, buffer, projectRoot);
} else {
result.error = std::move(fatal);
}
lc.DisposeTranslationUnit(tu);
lc.DisposeIndex(index);
lc.disposeTranslationUnit(tu);
lc.disposeIndex(index);
return result;
}

View file

@ -71,12 +71,12 @@ namespace Crafter {
std::string src = contents.str();
std::string pathStr = path.string();
const char* file_name_list[1] = { pathStr.c_str() };
const char* fileNameList[1] = { pathStr.c_str() };
const char* shaderSource = src.data();
const std::int32_t shaderSourceLen = static_cast<std::int32_t>(src.size());
glslang::TShader shader(glslangType);
shader.setStringsWithLengthsAndNames(&shaderSource, &shaderSourceLen, file_name_list, 1);
shader.setStringsWithLengthsAndNames(&shaderSource, &shaderSourceLen, fileNameList, 1);
shader.setEntryPoint(entrypoint.c_str());
shader.setSourceEntryPoint(entrypoint.c_str());
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_4);