#include "highlight.hpp"
#include "CgStr.hpp"
#include "config.hpp"
#include "debug.hpp"
#include <cstring>
#include <iostream>
using namespace synth;
unsigned const kMaxRefRecursion = 16;
bool synth::isTypeAliasCursorKind(CXCursorKind k)
{
return k == CXCursor_TypeAliasDecl
|| k == CXCursor_TypeAliasTemplateDecl
|| k == CXCursor_TypedefDecl;
}
bool synth::isTypeCursorKind(CXCursorKind k)
{
SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
switch (k) {
case CXCursor_ClassDecl:
case CXCursor_ClassTemplate:
case CXCursor_ClassTemplatePartialSpecialization:
case CXCursor_StructDecl:
case CXCursor_UnionDecl:
case CXCursor_EnumDecl:
case CXCursor_ObjCInterfaceDecl:
case CXCursor_ObjCCategoryDecl:
case CXCursor_ObjCProtocolDecl:
case CXCursor_ObjCImplementationDecl:
case CXCursor_TemplateTypeParameter:
case CXCursor_TemplateTemplateParameter:
case CXCursor_TypeRef:
case CXCursor_ObjCSuperClassRef:
case CXCursor_ObjCProtocolRef:
case CXCursor_ObjCClassRef:
case CXCursor_CXXBaseSpecifier:
return true;
default:
return isTypeAliasCursorKind(k);
}
SYNTH_DISCLANGWARN_END
}
bool synth::isFunctionCursorKind(CXCursorKind k)
{
SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
switch (k) {
case CXCursor_FunctionDecl:
case CXCursor_ObjCInstanceMethodDecl:
case CXCursor_ObjCClassMethodDecl:
case CXCursor_CXXMethod:
case CXCursor_FunctionTemplate:
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_ConversionFunction:
case CXCursor_OverloadedDeclRef:
return true;
default:
return false;
}
SYNTH_DISCLANGWARN_END
}
static TokenAttributes getVarTokenAttributes(CXCursor cur)
{
if (clang_getCursorLinkage(cur) == CXLinkage_NoLinkage)
return TokenAttributes::varLocal;
if (clang_getCXXAccessSpecifier(cur) == CX_CXXInvalidAccessSpecifier)
return TokenAttributes::varGlobal;
if (clang_Cursor_getStorageClass(cur) == CX_SC_Static)
return TokenAttributes::varStaticMember;
return TokenAttributes::varNonstaticMember;
}
static TokenAttributes getIntTokenAttributes(boost::string_ref sp)
{
if (!sp.empty()) {
if (sp.size() >= 2 && sp[0] == '0') {
if (sp[1] == 'x' || sp[1] == 'X')
return TokenAttributes::litNumIntHex;
if (sp[1] == 'b' || sp[1] == 'B')
return TokenAttributes::litNumIntBin;
return TokenAttributes::litNumIntOct;
}
char suffix = sp[sp.size() - 1];
if (suffix == 'l' || suffix == 'L')
return TokenAttributes::litNumIntDecLong;
}
return TokenAttributes::litNum;
}
static bool isBuiltinTypeKw(boost::string_ref t) {
return t.starts_with("unsigned ")
|| t == "unsigned"
|| t.starts_with("signed ")
|| t == "signed"
|| t.starts_with("short ")
|| t == "short"
|| t.starts_with("long ")
|| t == "long"
|| t == "int"
|| t == "float"
|| t == "double"
|| t == "bool"
|| t == "char"
|| t == "char16_t"
|| t == "char32_t"
|| t == "wchar_t"
|| t == "void";
}
static TokenAttributes getTokenAttributesImpl(
CXToken tok,
CXCursor cur,
boost::string_ref sp, // token spelling
CXTranslationUnit tu,
unsigned recursionDepth)
{
CXCursorKind k = clang_getCursorKind(cur);
CXTokenKind tk = clang_getTokenKind(tok);
if (clang_isPreprocessing(k)) {
if (k == CXCursor_InclusionDirective && sp != "include" && sp != "#")
return TokenAttributes::preIncludeFile;
return TokenAttributes::pre;
}
switch (tk) {
case CXToken_Punctuation:
if (k == CXCursor_BinaryOperator || k == CXCursor_UnaryOperator)
return TokenAttributes::op;
return TokenAttributes::punct;
case CXToken_Comment:
return TokenAttributes::cmmt;
case CXToken_Literal:
SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
switch (k) {
case CXCursor_ObjCStringLiteral:
case CXCursor_StringLiteral:
return TokenAttributes::litStr;
case CXCursor_CharacterLiteral:
return TokenAttributes::litChr;
case CXCursor_FloatingLiteral:
return TokenAttributes::litNumFlt;
case CXCursor_IntegerLiteral:
return getIntTokenAttributes(sp);
case CXCursor_ImaginaryLiteral:
return TokenAttributes::litNum;
default:
return TokenAttributes::lit;
}
SYNTH_DISCLANGWARN_END
case CXToken_Keyword: {
if (k == CXCursor_BinaryOperator || k == CXCursor_UnaryOperator)
return TokenAttributes::opWord;
if (k == CXCursor_CXXNullPtrLiteralExpr
|| k == CXCursor_CXXBoolLiteralExpr
|| k == CXCursor_ObjCBoolLiteralExpr
) {
return TokenAttributes::litKw;
}
if (k == CXCursor_TypeRef || isBuiltinTypeKw(sp))
return TokenAttributes::tyBuiltin;
if (clang_isDeclaration(k) || k == CXCursor_DeclStmt)
return TokenAttributes::kwDecl;
if (sp == "sizeof" || sp == "alignof")
return TokenAttributes::opWord;
if (sp == "this")
return TokenAttributes::litKw;
return TokenAttributes::kw;
}
case CXToken_Identifier:
if (isTypeCursorKind(k))
return TokenAttributes::ty;
if (isFunctionCursorKind(k))
return TokenAttributes::func;
SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
switch (k) {
case CXCursor_ObjCPropertyDecl:
return TokenAttributes::varNonstaticMember; // Sorta right.
case CXCursor_ObjCIvarDecl:
case CXCursor_FieldDecl:
return TokenAttributes::varNonstaticMember; // TODO
case CXCursor_EnumConstantDecl:
case CXCursor_NonTypeTemplateParameter:
return TokenAttributes::constant;
case CXCursor_VarDecl:
return getVarTokenAttributes(cur);
case CXCursor_ParmDecl:
return TokenAttributes::varLocal;
case CXCursor_Namespace:
case CXCursor_NamespaceAlias:
case CXCursor_UsingDirective:
case CXCursor_NamespaceRef:
return TokenAttributes::namesp;
case CXCursor_LabelStmt:
return TokenAttributes::lbl;
default: {
if (clang_isAttribute(k))
return TokenAttributes::attr;
CXCursor refd = clang_getCursorReferenced(cur);
bool recErr = recursionDepth > kMaxRefRecursion;
if (recErr) {
CgStr kindSp(clang_getCursorKindSpelling(k));
CgStr rKindSp(clang_getCursorKindSpelling(
clang_getCursorKind(refd)));
std::clog << "When trying to highlight token "
<< clang_getTokenExtent(tu, tok) << " "
<< sp << ":\n"
<< " Cursor " << clang_getCursorExtent(cur)
<< " " << kindSp << " references "
<< clang_getCursorExtent(refd)
<< " " << rKindSp
<< " Maximum depth exceeded with "
<< recursionDepth << ".\n";
return TokenAttributes::none;
}
if (clang_equalCursors(cur, refd))
return TokenAttributes::none;
return getTokenAttributesImpl(
tok, refd, sp, tu, recursionDepth + 1);
}
}
}
SYNTH_DISCLANGWARN_END
assert("unreachable" && false);
return TokenAttributes::none;
}
TokenAttributes synth::getTokenAttributes(
CXToken tok, CXCursor cur, boost::string_ref tokSpelling)
{
return getTokenAttributesImpl(
tok, cur, tokSpelling, clang_Cursor_getTranslationUnit(cur), 0);
}