clang.cpp 32.6 KB
Newer Older
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
1 2 3 4 5 6 7 8 9 10 11 12 13
#include "stdafx.h"

#pragma warning( disable : 4141 4244 4291 4624 4800 4996 4267)

#include "boost/tokenizer.hpp"

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"

#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
ussrhero's avatar
ussrhero committed
14 15 16
#include "clang/Parse/ParseAST.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Driver/Driver.h"
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
17 18 19 20 21 22

#include "kdlib/typeinfo.h"
#include "kdlib/exceptions.h"

#include "strconvert.h"
#include "clang.h"
ussrhero's avatar
ussrhero committed
23
#include "fnmatch.h"
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
24 25 26 27

using namespace clang;
using namespace clang::tooling;

ussrhero's avatar
ussrhero committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
namespace {
    
std::string getFunctionNameFromDecl(FunctionDecl* funcDec)
{
    SmallString<64> buf;
    llvm::raw_svector_ostream stream(buf);
    LangOptions  lo;
    PrintingPolicy pp(lo);
    pp.SuppressTagKeyword = true;
    pp.MSVCFormatting = true;
    funcDec->getNameForDiagnostic(stream, pp, true);
    return stream.str();
}

std::string getRecordNameFromDecl(CXXRecordDecl* decl)
{
    auto templateSpecialization = llvm::dyn_cast<ClassTemplateSpecializationDecl>(decl);
    if (templateSpecialization)
    {
        SmallString<64> buf;
        llvm::raw_svector_ostream stream(buf);
        LangOptions  lo;
        PrintingPolicy pp(lo);
        pp.SuppressTagKeyword = true;
        pp.MSVCFormatting = true;
        templateSpecialization->getNameForDiagnostic(stream, pp, true);
        return stream.str();
    }

    return decl->getQualifiedNameAsString();
}

}

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
62 63 64 65 66 67
namespace kdlib{

TypeInfoPtr getTypeForClangBuiltinType(const clang::BuiltinType* builtinType)
{
    switch( builtinType->getKind() )
    {
68
    case clang::BuiltinType::Void:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
69 70
        return TypeInfoPtr( new TypeInfoVoid() );

71
    case clang::BuiltinType::Bool:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
72
        return loadType(L"Bool");
73
    case clang::BuiltinType::Char_S:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
74
        return loadType(L"Char");
75
    case clang::BuiltinType::WChar_S:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
76 77
        return loadType(L"WChar");

78
    case clang::BuiltinType::UChar:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
79
        return loadType(L"UInt1B");
80 81
    case clang::BuiltinType::WChar_U:
    case clang::BuiltinType::UShort:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
82
        return loadType(L"UInt2B");
83 84
    case clang::BuiltinType::UInt:
    case clang::BuiltinType::ULong:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
85
        return loadType(L"UInt4B");
86
    case clang::BuiltinType::ULongLong:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
87 88
        return loadType(L"UInt8B");

89
    case clang::BuiltinType::Short:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
90
        return loadType(L"Int2B");
91 92
    case clang::BuiltinType::Int:
    case clang::BuiltinType::Long:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
93
        return loadType(L"Int4B");
94
    case clang::BuiltinType::LongLong:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
95 96
        return loadType(L"Int8B");

97
    case clang::BuiltinType::Float:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
98
        return loadType(L"Float");
99 100
    case clang::BuiltinType::Double:
    case clang::BuiltinType::LongDouble:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
101 102 103 104 105 106 107 108 109 110 111 112
        return loadType(L"Double");
    }

    throw ClangException(L"Unknown base type");
}



TypeInfoPtr getTypeForClangType( ClangASTSessionPtr&  astSession, const clang::QualType& qualType )
{
    if ( qualType->isBuiltinType() )
    {
113 114
        const BuiltinType*  builtin = qualType->getAs<BuiltinType>();
        return getTypeForClangBuiltinType(builtin);
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
115 116 117 118
    }

    if ( qualType->isPointerType() )
    {
119
         const PointerType*  ptr = qualType->getAs<PointerType>();
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
120 121 122 123 124
         return TypeInfoPtr( new TypeInfoClangPointer(astSession, ptr));
    }

    if ( qualType->isArrayType() )
    {
125
        const ArrayType*  arrayType = qualType->getAsArrayTypeUnsafe();
ussrhero's avatar
ussrhero committed
126 127 128
        if (llvm::isa<clang::IncompleteArrayType>(arrayType))
            return TypeInfoPtr( new TypeInfoIncompleteClangArray(astSession, arrayType));

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
129 130 131 132 133
        return TypeInfoPtr( new TypeInfoClangArray(astSession, arrayType ) );
    }

    if ( qualType->isReferenceType() )
    {
134
        const ReferenceType*  refType = qualType->getAs<ReferenceType>();
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
135 136 137
        return TypeInfoPtr( new TypeInfoClangRef(astSession, refType ) );
    }

138
    if ( qualType->isRecordType() )
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
139
    {
140
       RecordDecl*  decl = llvm::dyn_cast<clang::RecordDecl>(qualType->getAsTagDecl());
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
141 142 143 144
       if ( decl->getDefinition() )
           return TypeInfoPtr( new TypeInfoClangStruct( strToWStr(decl->getNameAsString()), astSession, decl->getDefinition() ) );
       else
           return TypeInfoPtr( new TypeInfoClangStructNoDef( strToWStr(decl->getNameAsString()), astSession, decl ) );
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
145 146
    }

147
    if ( qualType->isFunctionProtoType() )
148
    {
ussrhero's avatar
ussrhero committed
149
        auto  funcProto = qualType->getAs<FunctionProtoType>();
150

ussrhero's avatar
ussrhero committed
151
        return TypeInfoPtr( new TypeInfoClangFuncPrototype(astSession, funcProto) );
152 153 154 155 156 157
    }

    if ( qualType->isEnumeralType() )
    {
        EnumDecl*  decl = llvm::dyn_cast<EnumDecl>(qualType->getAsTagDecl());
        return TypeInfoPtr( new TypeInfoClangEnum(astSession, decl) );
158 159
    }

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    throw TypeException(L"can not parse code");
}

///////////////////////////////////////////////////////////////////////////////

TypeFieldPtr TypeFieldClangField::getField(ClangASTSessionPtr& astSession, clang::RecordDecl* structDecl, clang::FieldDecl* fieldDecl, MEMOFFSET_32 startOffset)
{
    clang::NamedDecl *nameDecl = llvm::dyn_cast<clang::NamedDecl> (fieldDecl);
    if (!nameDecl)
        throw ClangException();

    std::string   name = nameDecl->getNameAsString();

    TypeFieldClangField  *field = new TypeFieldClangField(strToWStr(name));

    field->m_astSession = astSession;
    field->m_fieldDecl = fieldDecl;
    field->m_recordDecl = structDecl;

    const ASTRecordLayout  &typeLayout = fieldDecl->getASTContext().getASTRecordLayout(structDecl);

    field->m_offset = startOffset + typeLayout.getFieldOffset(fieldDecl->getFieldIndex()) / 8;

    return TypeFieldPtr(field);
}

///////////////////////////////////////////////////////////////////////////////

TypeFieldPtr TypeFieldClangField::getStaticField(ClangASTSessionPtr& astSession,  clang::RecordDecl* structDecl, clang::VarDecl* varDecl)
{
    clang::NamedDecl *nameDecl = llvm::dyn_cast<clang::NamedDecl> (varDecl);
    if (!nameDecl)
        throw ClangException();

    std::string   name = nameDecl->getNameAsString();

    TypeFieldClangField  *field = new TypeFieldClangField(strToWStr(name));

    field->m_astSession = astSession;
    field->m_fieldDecl = varDecl;
    field->m_staticMember = true;

    return TypeFieldPtr(field);
}

///////////////////////////////////////////////////////////////////////////////

TypeInfoPtr TypeFieldClangField::getTypeInfo()
{
    const clang::QualType qualType = m_fieldDecl->getType().getLocalUnqualifiedType().getCanonicalType();

211
    if ( qualType->isRecordType() )
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
212
    {
213
        RecordDecl*  decl = llvm::dyn_cast<clang::RecordDecl>(qualType->getAsTagDecl());
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
214 215 216

        std::string  name = decl->getNameAsString();
        if ( name.empty() )
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
217 218 219 220 221
        {
            std::stringstream  sstr;
            sstr << m_recordDecl->getNameAsString() << "::<unnamed-type-" << wstrToStr(getName()) << '>';
            name = sstr.str();
        }
ussrhero's avatar
ussrhero committed
222 223
 return TypeInfoPtr( new TypeInfoClangStruct( strToWStr(name), m_astSession, decl->getDefinition() ) );
      
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
224 225 226 227 228 229 230 231 232 233 234 235 236
    }

    clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(m_fieldDecl);
    if ( fieldDecl )
    {
        if ( fieldDecl->isBitField() )
        {
            TypeInfoPtr   bitType = getTypeForClangType(m_astSession, qualType);

            unsigned int bitWidth = fieldDecl->getBitWidthValue(m_astSession->getASTContext());

            const ASTRecordLayout  &typeLayout = fieldDecl->getASTContext().getASTRecordLayout(m_recordDecl);

237 238 239
            size_t  bitOffset = typeLayout.getFieldOffset(fieldDecl->getFieldIndex());
            
            bitOffset %= bitType->getSize() * 8;
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
240 241 242 243 244 245 246 247 248 249

            return TypeInfoPtr( new TypeInfoBitField(bitType, bitOffset, bitWidth) );
        }
    }

    return getTypeForClangType(m_astSession, qualType);
}

///////////////////////////////////////////////////////////////////////////////

SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
250
TypeInfoClangStruct::TypeInfoClangStruct(const std::wstring & name, ClangASTSessionPtr& session, clang::RecordDecl*  decl) :
251
        TypeInfoFields(name),
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
252 253 254
        m_astSession(session),
        m_decl(decl)
{
ussrhero's avatar
ussrhero committed
255 256
   // if ( decl->isInvalidDecl() )
   ///     throw TypeException(L"Invalid declaration");
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
257 258 259 260
}

///////////////////////////////////////////////////////////////////////////////

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
261 262 263 264 265 266 267
void TypeInfoClangStruct::getFields()
{
    getRecursiveFields( m_decl, 0 );
}

///////////////////////////////////////////////////////////////////////////////

268
void TypeInfoClangStruct::getRecursiveFields( clang::RecordDecl* recordDecl, MEMOFFSET_32 startOffset)
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
269
{
270 271
    getFieldFromBaseClasses(recordDecl, startOffset);

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    const ASTRecordLayout  &typeLayout = recordDecl->getASTContext().getASTRecordLayout(recordDecl);

    for(clang::RecordDecl::decl_iterator  declit = recordDecl->decls_begin(); declit != recordDecl->decls_end(); declit++)
    {

        clang::NamedDecl *nameDecl = llvm::dyn_cast<clang::NamedDecl> (*declit);
        if (!nameDecl)
            continue;

        std::string   name = nameDecl->getNameAsString();

        clang::FieldDecl *fieldDecl = llvm::dyn_cast<clang::FieldDecl>(*declit);
        if ( fieldDecl )
        {
            if ( name.empty() )
            {
                const clang::QualType qualType = fieldDecl->getType().getLocalUnqualifiedType().getCanonicalType();
289
                if ( qualType->isRecordType() )
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
290 291
                {
                    MEMOFFSET_32  fieldOffset = typeLayout.getFieldOffset(fieldDecl->getFieldIndex()) / 8;
292
                    getRecursiveFields( llvm::dyn_cast<clang::RecordDecl>(qualType->getAsTagDecl()), startOffset + fieldOffset );
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
293 294 295 296
                }
            }
            else
            {
297 298 299 300 301

                auto field = TypeFieldClangField::getField(m_astSession, recordDecl, fieldDecl, startOffset);
                if (recordDecl != m_decl)
                    field->setMemberInherited();
                m_fields.push_back(field);
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
302 303 304 305 306 307 308
                continue;
            }
        }

        clang::VarDecl *varDecl = llvm::dyn_cast<clang::VarDecl>(*declit);
        if ( varDecl )
        {
309 310 311 312
            auto field = TypeFieldClangField::getStaticField(m_astSession, recordDecl, varDecl);
            if (recordDecl != m_decl)
                field->setMemberInherited();
            m_fields.push_back(field);
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
313 314
            continue;
        }
ussrhero's avatar
ussrhero committed
315 316 317 318 319 320 321 322 323 324 325

        clang::EnumDecl  * enumDecl = llvm::dyn_cast<clang::EnumDecl>(*declit);
        if ( enumDecl )
        {
            for (clang::EnumDecl::enumerator_iterator enumIt = enumDecl->enumerator_begin(); enumIt != enumDecl->enumerator_end(); ++enumIt)
            {
                std::string   fieldName = enumIt->getNameAsString();

                m_fields.push_back(TypeFieldClangEnumField::getField(m_astSession, *enumIt));
            }
        }
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
326 327 328 329 330
    }
}

///////////////////////////////////////////////////////////////////////////////

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
void TypeInfoClangStruct::getFieldFromBaseClasses(clang::RecordDecl* recordDecl, MEMOFFSET_32 startOffset)
{
    const CXXRecordDecl  *classDecl = llvm::dyn_cast<clang::CXXRecordDecl>(recordDecl);

    if (!classDecl)
        return;
        
    for (auto baseIt : classDecl->bases())
    {
        auto  baseDecl = baseIt.getType()->getAsCXXRecordDecl();
        auto  baseOffset = recordDecl->getASTContext().getASTRecordLayout(m_decl).getBaseClassOffset( baseIt.getType()->getAsCXXRecordDecl() ).getQuantity();

        getRecursiveFields(baseDecl, startOffset + baseOffset);
    }
}

///////////////////////////////////////////////////////////////////////////////

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
349 350 351 352 353 354
size_t TypeInfoClangStruct::getSize()
{
    const ASTRecordLayout  &typeLayout = m_decl->getASTContext().getASTRecordLayout(m_decl);
    return typeLayout.getSize().getQuantity();
}

SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
355 356
///////////////////////////////////////////////////////////////////////////////

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
size_t TypeInfoClangStruct::getBaseClassesCount()
{
    const CXXRecordDecl  *classDecl = llvm::dyn_cast<clang::CXXRecordDecl>(m_decl);

    if (!classDecl)
        return 0;
    
    return std::distance(classDecl->bases_begin(), classDecl->bases_end());
}

///////////////////////////////////////////////////////////////////////////////

TypeInfoPtr TypeInfoClangStruct::getBaseClass(const std::wstring& className)
{
    const CXXRecordDecl  *classDecl = llvm::dyn_cast<clang::CXXRecordDecl>(m_decl);

    if (!classDecl)
        throw TypeException(L"Type has no base class");

    for (auto baseIt : classDecl->bases())
    {
        if (baseIt.getType()->getAsCXXRecordDecl()->getNameAsString() == wstrToStr(className))
            return getTypeForClangType(m_astSession, baseIt.getType());
    }

    std::wstringstream  sstr;
    sstr << getName() << " has no this base class : " << className;
    throw TypeException(sstr.str());
}

///////////////////////////////////////////////////////////////////////////////

TypeInfoPtr TypeInfoClangStruct::getBaseClass(size_t index)
{
    const CXXRecordDecl  *classDecl = llvm::dyn_cast<clang::CXXRecordDecl>(m_decl);

    if (!classDecl)
        throw TypeException(L"Type has no base class");

    if (index >= getBaseClassesCount())
        throw IndexException(index);

    return getTypeForClangType(m_astSession, std::next(classDecl->bases_begin(), index)->getType());
}

///////////////////////////////////////////////////////////////////////////////

MEMOFFSET_REL TypeInfoClangStruct::getBaseClassOffset(const std::wstring &className)
{
    const CXXRecordDecl  *classDecl = llvm::dyn_cast<clang::CXXRecordDecl>(m_decl);

    if (!classDecl)
        throw TypeException(L"Type has no base class");

    for (auto baseIt : classDecl->bases())
    {
        if (baseIt.getType()->getAsCXXRecordDecl()->getNameAsString() == wstrToStr(className))
        {
            return m_decl->getASTContext().getASTRecordLayout(m_decl).getBaseClassOffset(
                baseIt.getType()->getAsCXXRecordDecl()
            ).getQuantity();
        }
    }

    std::wstringstream  sstr;
    sstr << getName() << " has no this base class : " << className;
    throw TypeException(sstr.str());
}

///////////////////////////////////////////////////////////////////////////////

MEMOFFSET_REL TypeInfoClangStruct::getBaseClassOffset(size_t index)
{
    const CXXRecordDecl  *classDecl = llvm::dyn_cast<clang::CXXRecordDecl>(m_decl);

    if (!classDecl)
        throw TypeException(L"Type has no base class");

    if (index >= getBaseClassesCount())
        throw IndexException(index);

    return m_decl->getASTContext().getASTRecordLayout(m_decl).getBaseClassOffset(
        std::next(classDecl->bases_begin(), index)->getType()->getAsCXXRecordDecl()
    ).getQuantity();

}

///////////////////////////////////////////////////////////////////////////////

SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
446 447 448 449
std::wstring TypeInfoClangStructNoDef::str()
{
    return std::wstring(L"forward declaration class/struct : ") +  m_name;
}
450

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
451 452
///////////////////////////////////////////////////////////////////////////////

453
TypeInfoPtr TypeInfoClangPointer::getDerefType( ClangASTSessionPtr& astSession, const clang::PointerType* refType)
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
454 455 456 457 458 459
{
    return getTypeForClangType(astSession, refType->getPointeeType());
}

///////////////////////////////////////////////////////////////////////////////

460
TypeInfoPtr TypeInfoClangArray::getDerefType( ClangASTSessionPtr& astSession, const clang::ArrayType* arrayType)
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
461 462 463 464 465 466
{
    return getTypeForClangType(astSession, arrayType->getElementType());
}

///////////////////////////////////////////////////////////////////////////////

467
size_t TypeInfoClangArray::getElementCount(const clang::ArrayType* arrayType)
468
{
469
    const ConstantArrayType*  constArray = llvm::dyn_cast<ConstantArrayType>(arrayType);
470 471 472 473 474 475 476 477
    if ( constArray )
        return  constArray->getSize().getSExtValue();

    return 0;
}

///////////////////////////////////////////////////////////////////////////////

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
478 479 480 481 482 483 484
TypeInfoPtr TypeInfoClangRef::deref()
{
    return getTypeForClangType(m_astSession, m_refType->getPointeeType());
}

///////////////////////////////////////////////////////////////////////////////

ussrhero's avatar
ussrhero committed
485
TypeInfoClangFuncPrototype::TypeInfoClangFuncPrototype(ClangASTSessionPtr& session, const FunctionProtoType* funcProto)
486
{
ussrhero's avatar
ussrhero committed
487

488 489
    m_returnType = getTypeForClangType(session, funcProto->getReturnType());

ussrhero's avatar
ussrhero committed
490
    switch (funcProto->getCallConv())
491 492
    {
    case CC_C:
ussrhero's avatar
ussrhero committed
493 494
        m_callconv = CallConv_NearC;
        break;
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

    case CC_X86StdCall:
        m_callconv = CallConv_NearStd;
        break;

    case CC_X86FastCall:
        m_callconv = CallConv_NearFast;
        break;

    case CC_X86ThisCall:
        m_callconv = CallConv_ThisCall;
        break;

    default:
        throw TypeException(L"unsupported calling conversion");

    }

ussrhero's avatar
ussrhero committed
513 514 515 516 517 518 519 520 521 522 523 524
    for (clang::FunctionProtoType::param_type_iterator paramIt = funcProto->param_type_begin(); paramIt != funcProto->param_type_end(); paramIt++)
    {
        m_args.push_back(getTypeForClangType(session, *paramIt));
    }
}
///////////////////////////////////////////////////////////////////////////////

TypeInfoClangFunc::TypeInfoClangFunc(ClangASTSessionPtr& session, clang::FunctionDecl*  funcDecl) :
    TypeInfoClangFuncPrototype(session, funcDecl->getFunctionType()->getAs< FunctionProtoType>() )
{
    CXXRecordDecl  *parentClassDecl = llvm::dyn_cast<CXXRecordDecl>(funcDecl->getDeclContext());
    if (parentClassDecl)
525
    {
ussrhero's avatar
ussrhero committed
526 527
        auto  name = strToWStr(getRecordNameFromDecl(parentClassDecl));
        m_classParent = TypeInfoPtr(new TypeInfoClangStruct(name, session, parentClassDecl->getDefinition()));
528 529 530 531 532 533 534 535 536 537 538 539 540
    }
}

///////////////////////////////////////////////////////////////////////////////

TypeFieldPtr TypeFieldClangEnumField::getField(ClangASTSessionPtr& astSession, clang::EnumConstantDecl*  EnumDecl)
{
    std::string   name = EnumDecl->getNameAsString();

    TypeFieldClangEnumField  *field = new TypeFieldClangEnumField(strToWStr(name));

    field->m_decl = EnumDecl;
    field->m_astSession = astSession;
ussrhero's avatar
ussrhero committed
541
    field->m_constMember = true;    
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573

    return TypeFieldPtr(field);
}

///////////////////////////////////////////////////////////////////////////////

TypeInfoPtr TypeFieldClangEnumField::getTypeInfo()
{
    return makeULongConst( static_cast<unsigned long>(m_decl->getInitVal().getExtValue() ) );
}

///////////////////////////////////////////////////////////////////////////////

NumVariant TypeFieldClangEnumField::getValue() const
{
    return NumVariant( m_decl->getInitVal().getExtValue() );
}

///////////////////////////////////////////////////////////////////////////////

void TypeInfoClangEnum::getFields()
{
    for ( clang::EnumDecl::enumerator_iterator  enumIt = m_decl->enumerator_begin(); enumIt != m_decl->enumerator_end(); ++enumIt )
    {
        std::string   fieldName = enumIt->getNameAsString();

        m_fields.push_back( TypeFieldClangEnumField::getField(m_astSession, *enumIt) );
    }
}

///////////////////////////////////////////////////////////////////////////////

574
class DeclNextVisitor : public RecursiveASTVisitor<DeclNextVisitor>
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
575 576
{

ussrhero's avatar
ussrhero committed
577
public:
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
578

ussrhero's avatar
ussrhero committed
579
    DeclNextVisitor(ClangASTSessionPtr& astSession, std::map<std::string, TypeInfoPtr>* typeMap) :
ussrhero's avatar
ussrhero committed
580
        m_session(astSession),
ussrhero's avatar
ussrhero committed
581
        m_typeMap(typeMap)
582
    {}
ussrhero's avatar
ussrhero committed
583 584 585 586 587 588

    bool VisitCXXRecordDecl(CXXRecordDecl *Declaration)
    {
        try {

            CXXRecordDecl *   definition = Declaration->getDefinition();
ussrhero's avatar
ussrhero committed
589

590 591 592 593 594 595 596 597 598 599 600
            if (definition)
            {
                if (definition->isInvalidDecl())
                    return true;

                auto  templateDecl = definition->getDescribedClassTemplate();

                if (templateDecl)
                {
                    for (auto specIt = templateDecl->spec_begin(); specIt != templateDecl->spec_end(); specIt++)
                    {
601 602 603
                        LangOptions  lo;
                        PrintingPolicy pp(lo);
                        pp.SuppressTagKeyword = true;
ussrhero's avatar
ussrhero committed
604 605
                        pp.MSVCFormatting = true;

ussrhero's avatar
ussrhero committed
606
                        const std::string  &name = (*specIt)->getTypeForDecl()->getCanonicalTypeInternal().getAsString(pp);
607

608
                        auto  rr = llvm::dyn_cast<CXXRecordDecl>(*specIt);
ussrhero's avatar
ussrhero committed
609

610 611
                        auto typeInfo = TypeInfoPtr(new TypeInfoClangStruct(strToWStr(name), m_session, rr));
                        (*m_typeMap)[name] = typeInfo;
612 613 614 615
                    }
                }
                else
                {
ussrhero's avatar
ussrhero committed
616
                    const std::string  &name = Declaration->getQualifiedNameAsString();
617 618 619
                    (*m_typeMap)[name] = TypeInfoPtr(new TypeInfoClangStruct(strToWStr(name), m_session, definition));
                }
            }
ussrhero's avatar
ussrhero committed
620
            else
621
            {
622
                const std::string  &name = Declaration->getQualifiedNameAsString();
623 624
                (*m_typeMap)[name] = TypeInfoPtr(new TypeInfoClangStructNoDef(strToWStr(name), m_session, Declaration));
            }
ussrhero's avatar
ussrhero committed
625 626 627 628
        }
        catch (TypeException&)
        {
        }
ussrhero's avatar
ussrhero committed
629 630 631 632

        return true;
    }

ussrhero's avatar
ussrhero committed
633
    bool VisitTypedefDecl(TypedefDecl  *Declaration)
ussrhero's avatar
ussrhero committed
634
    {
ussrhero's avatar
ussrhero committed
635

ussrhero's avatar
ussrhero committed
636 637
        try {

638
            if (Declaration->isInvalidDecl())
ussrhero's avatar
ussrhero committed
639 640
                return true;

ussrhero's avatar
ussrhero committed
641
            const std::string&  name = Declaration->getQualifiedNameAsString();
ussrhero's avatar
ussrhero committed
642 643 644 645 646

            QualType  decl = Declaration->getUnderlyingType().getCanonicalType();

            (*m_typeMap)[name] = getTypeForClangType(m_session, decl);

647 648 649 650
        }
        catch (TypeException&)
        {
        }
ussrhero's avatar
ussrhero committed
651 652 653 654 655 656 657 658 659

        return true;
    }


    bool VisitFunctionDecl(FunctionDecl *Declaration)
    {
        try {

660
            if (Declaration->isInvalidDecl())
ussrhero's avatar
ussrhero committed
661 662
                return true;

663
            if (Declaration->getTemplatedKind() == FunctionDecl::TemplatedKind::TK_FunctionTemplate)
ussrhero's avatar
ussrhero committed
664 665
                return true;

666
            if (CXXRecordDecl  *parentClassDecl = llvm::dyn_cast<CXXRecordDecl>(Declaration->getDeclContext()))
ussrhero's avatar
ussrhero committed
667
            {
668
                if (parentClassDecl->getDescribedClassTemplate())
ussrhero's avatar
ussrhero committed
669 670 671
                    return true;
            }

ussrhero's avatar
ussrhero committed
672
            std::string  name = getFunctionNameFromDecl(Declaration);
ussrhero's avatar
ussrhero committed
673

ussrhero's avatar
ussrhero committed
674
            TypeInfoPtr  typeInfo = TypeInfoPtr(new TypeInfoClangFunc(m_session, Declaration));
ussrhero's avatar
ussrhero committed
675

ussrhero's avatar
ussrhero committed
676
            (*m_typeMap)[name] = typeInfo;
ussrhero's avatar
ussrhero committed
677

678 679 680 681
        }
        catch (TypeException&)
        {
        }
ussrhero's avatar
ussrhero committed
682 683 684 685

        return true;
    }

686
    bool VisitEnumDecl(EnumDecl *Declaration)
ussrhero's avatar
ussrhero committed
687
    {
688 689
        try {
            if (Declaration->isInvalidDecl())
ussrhero's avatar
ussrhero committed
690 691
                return true;

ussrhero's avatar
ussrhero committed
692
            std::string  name = Declaration->getQualifiedNameAsString();
ussrhero's avatar
ussrhero committed
693

694 695
            TypeInfoPtr  typeInfo = TypeInfoPtr(new TypeInfoClangEnum(m_session, Declaration));

ussrhero's avatar
ussrhero committed
696

ussrhero's avatar
ussrhero committed
697
            (*m_typeMap)[name] = typeInfo;
ussrhero's avatar
ussrhero committed
698

699 700 701 702
        }
        catch (TypeException&)
        {
        }
ussrhero's avatar
ussrhero committed
703 704 705 706 707 708 709 710 711

        return true;
    }

private:


    ClangASTSessionPtr  m_session;

ussrhero's avatar
ussrhero committed
712
    std::map<std::string, TypeInfoPtr>  *m_typeMap;
ussrhero's avatar
ussrhero committed
713
};
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
714 715 716

///////////////////////////////////////////////////////////////////////////////

717 718 719 720 721
class FuncVisitor : public RecursiveASTVisitor<FuncVisitor>
{

public:

ussrhero's avatar
ussrhero committed
722
    FuncVisitor(ClangASTSessionPtr& astSession, SymbolList&  symbols) :
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
        m_session(astSession),
        m_symbols(symbols)
   {}


    bool VisitFunctionDecl(FunctionDecl *Declaration)
    {
        try {

            if ( Declaration->isInvalidDecl() )
                return true;

            if ( Declaration->getTemplatedKind() == FunctionDecl::TemplatedKind::TK_FunctionTemplate )
                return true;

ussrhero's avatar
ussrhero committed
738
            m_symbols.push_back(std::make_pair(getFunctionNameFromDecl(Declaration), Declaration));
739 740 741 742 743 744 745 746 747 748 749

        } catch(TypeException& )
        {}

        return true;
    }
private:


    ClangASTSessionPtr  m_session;

ussrhero's avatar
ussrhero committed
750
    SymbolList  &m_symbols;
751 752 753 754
};

///////////////////////////////////////////////////////////////////////////////

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
755 756 757 758 759 760 761 762 763
size_t ClangASTSession::getPtrSize()
{
    const Type*  sizeType = getASTContext().getSizeType()->getTypePtr();
    return static_cast<const clang::BuiltinType*>(sizeType)->getKind() ==  clang::BuiltinType::Kind::ULongLong  ? 8 : 4;
}

///////////////////////////////////////////////////////////////////////////////

TypeInfoPtr compileType( const std::wstring& sourceCode, const std::wstring& typeName, const std::wstring& options)
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
764 765 766 767 768 769
{
    return getTypeInfoProviderFromSource(sourceCode, options)->getTypeByName(typeName);
}

///////////////////////////////////////////////////////////////////////////////

ussrhero's avatar
ussrhero committed
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
class ASTBuilderAction : public clang::tooling::ToolAction
{
    std::vector<std::unique_ptr<ASTUnit>> &ASTs;

public:
    ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}

    bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
        FileManager *Files,
        std::shared_ptr<PCHContainerOperations> PCHContainerOps,
        DiagnosticConsumer *DiagConsumer) override {
        std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
            Invocation, std::move(PCHContainerOps),
            CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(),
                DiagConsumer,
                /*ShouldOwnClient=*/false),
            Files);

        if (!AST)
            return false;

        ASTs.push_back(std::move(AST));
        return true;
    }
ussrhero's avatar
ussrhero committed
794 795
};

ussrhero's avatar
ussrhero committed
796
TypeInfoProviderClang::TypeInfoProviderClang( const std::string& sourceCode, const std::string& compileOptions)
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
797
{
ussrhero's avatar
ussrhero committed
798 799 800 801 802 803 804 805 806 807
    std::vector<std::unique_ptr<ASTUnit>> ASTs;
    ASTBuilderAction Action(ASTs);
    llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem(
        new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
    llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
        new vfs::InMemoryFileSystem);
    OverlayFileSystem->pushOverlay(InMemoryFileSystem);
    llvm::IntrusiveRefCntPtr<FileManager> Files(
        new FileManager(FileSystemOptions(), OverlayFileSystem));

SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
808 809
    std::vector< std::string > args;

ussrhero's avatar
ussrhero committed
810 811
    args.push_back("clang-tool");
    args.push_back("-fsyntax-only");
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
812

ussrhero's avatar
ussrhero committed
813 814 815 816 817
    typedef boost::tokenizer< boost::escaped_list_separator<char> > Tokenizer;
    boost::escaped_list_separator<char> Separator('\\', ' ', '\"');

    Tokenizer tok(compileOptions, Separator);

ussrhero's avatar
ussrhero committed
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
    std::copy(tok.begin(), tok.end(), std::inserter(args, args.end()));

    args.push_back("input.cc");

    ToolInvocation toolInvocation(
        args,
        &Action, 
        Files.get(), 
        std::move(std::make_shared< PCHContainerOperations >())
    );

    InMemoryFileSystem->addFile("input.cc", 0, llvm::MemoryBuffer::getMemBuffer(sourceCode.c_str()));

#ifndef _DEBUG

    IgnoringDiagConsumer   diagnosticConsumer;

    toolInvocation.setDiagnosticConsumer(&diagnosticConsumer);

#endif

ussrhero's avatar
ussrhero committed
839 840 841
    toolInvocation.run();

    std::unique_ptr<ASTUnit>  ast = std::move(ASTs[0]);
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
842

SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
843
    m_astSession = ClangASTSession::getASTSession(ast);
ussrhero's avatar
ussrhero committed
844 845 846 847

    DeclNextVisitor   visitor(m_astSession, &m_typeCache);

    visitor.TraverseDecl( m_astSession->getASTContext().getTranslationUnitDecl() );
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
848 849 850 851
}

///////////////////////////////////////////////////////////////////////////////

SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
852 853
TypeInfoPtr TypeInfoProviderClang::getTypeByName(const std::wstring& name)
{
ussrhero's avatar
ussrhero committed
854
    auto  foundType = m_typeCache.find( wstrToStr(name) );
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
855

ussrhero's avatar
ussrhero committed
856 857 858 859 860
    if ( foundType == m_typeCache.end() )
        throw TypeException(name, L"Failed to get type");

    return foundType->second;
}
ussrhero's avatar
ussrhero committed
861 862 863 864 865

///////////////////////////////////////////////////////////////////////////////

TypeInfoEnumeratorPtr TypeInfoProviderClang::getTypeEnumerator(const std::wstring& mask) 
{
ussrhero's avatar
ussrhero committed
866
    return TypeInfoEnumeratorPtr( new TypeInfoProviderClangEnum(mask, shared_from_this()) );
ussrhero's avatar
ussrhero committed
867 868
}

SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
869
///////////////////////////////////////////////////////////////////////////////
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
870

ussrhero's avatar
ussrhero committed
871
TypeInfoProviderClangEnum::TypeInfoProviderClangEnum(const std::wstring& mask, const boost::shared_ptr<TypeInfoProviderClang>& clangProvider )
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
872
{
ussrhero's avatar
ussrhero committed
873 874 875 876 877 878 879 880 881 882
    m_index = 0;

    std::string  ansimask = wstrToStr(mask);

    std::for_each( clangProvider->m_typeCache.begin(), clangProvider->m_typeCache.end(),
        [&]( const std::pair<std::string, TypeInfoPtr> &it ) {
            if (ansimask.empty() || fnmatch(ansimask, it.first) )
                m_typeList.push_back(it.second);
        }
    );
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
883 884 885
}

///////////////////////////////////////////////////////////////////////////////
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
886

ussrhero's avatar
ussrhero committed
887 888
TypeInfoPtr TypeInfoProviderClangEnum::Next()
{
ussrhero's avatar
ussrhero committed
889 890 891
    if ( m_index < m_typeList.size() )
        return m_typeList[m_index++];
    return TypeInfoPtr();
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
892 893 894
}

///////////////////////////////////////////////////////////////////////////////
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
895

SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
896 897
TypeInfoProviderPtr  getTypeInfoProviderFromSource( const std::wstring&  source, const std::wstring&  opts )
{
ussrhero's avatar
ussrhero committed
898 899 900 901 902 903 904 905
    return TypeInfoProviderPtr( new TypeInfoProviderClang(wstrToStr(source), wstrToStr(opts) ) );
}

///////////////////////////////////////////////////////////////////////////////

TypeInfoProviderPtr  getTypeInfoProviderFromSource(const std::string&  source, const std::string&  opts)
{
    return TypeInfoProviderPtr(new TypeInfoProviderClang(source, opts));
SND\ussrhero_cp's avatar
SND\ussrhero_cp committed
906 907 908
}

///////////////////////////////////////////////////////////////////////////////
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
909

ussrhero's avatar
ussrhero committed
910
SymbolProviderClang::SymbolProviderClang(const std::string&  sourceCode, const std::string&  compileOptions)
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
{
    std::vector<std::unique_ptr<ASTUnit>> ASTs;
    ASTBuilderAction Action(ASTs);
    llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem(
        new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
    llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
        new vfs::InMemoryFileSystem);
    OverlayFileSystem->pushOverlay(InMemoryFileSystem);
    llvm::IntrusiveRefCntPtr<FileManager> Files(
        new FileManager(FileSystemOptions(), OverlayFileSystem));

    std::vector< std::string > args;

    args.push_back("clang-tool");
    args.push_back("-fsyntax-only");

    typedef boost::tokenizer< boost::escaped_list_separator<char> > Tokenizer;
    boost::escaped_list_separator<char> Separator('\\', ' ', '\"');

    Tokenizer tok(compileOptions, Separator);

    std::copy(tok.begin(), tok.end(), std::inserter(args, args.end()));

    args.push_back("input.cc");

    ToolInvocation toolInvocation(
        args,
        &Action,
        Files.get(),
        std::move(std::make_shared< PCHContainerOperations >())
    );

    InMemoryFileSystem->addFile("input.cc", 0, llvm::MemoryBuffer::getMemBuffer(sourceCode.c_str()));

#ifndef _DEBUG

    IgnoringDiagConsumer   diagnosticConsumer;

    toolInvocation.setDiagnosticConsumer(&diagnosticConsumer);

#endif

    toolInvocation.run();

    std::unique_ptr<ASTUnit>  ast = std::move(ASTs[0]);

ussrhero's avatar
ussrhero committed
957
    m_astSession = ClangASTSession::getASTSession(ast);
958

ussrhero's avatar
ussrhero committed
959
    FuncVisitor   visitor(m_astSession, m_symbols);
960

ussrhero's avatar
ussrhero committed
961
    visitor.TraverseDecl(m_astSession->getASTContext().getTranslationUnitDecl());
962 963 964 965
}

///////////////////////////////////////////////////////////////////////////////

ussrhero's avatar
ussrhero committed
966 967
SymbolEnumeratorPtr SymbolProviderClang::getSymbolEnumerator(const std::wstring& mask)
{
ussrhero's avatar
ussrhero committed
968
    return SymbolEnumeratorPtr(new SymbolEnumeratorClang(wstrToStr(mask), shared_from_this()));
ussrhero's avatar
ussrhero committed
969 970 971 972
}

///////////////////////////////////////////////////////////////////////////////

ussrhero's avatar
ussrhero committed
973
bool SymbolEnumeratorClang::Next()
974
{
ussrhero's avatar
ussrhero committed
975 976
    const auto& symbols = m_symbolProvider->m_symbols;

ussrhero's avatar
ussrhero committed
977
    while (m_index + 1 < symbols.size() )
ussrhero's avatar
ussrhero committed
978
    {
ussrhero's avatar
ussrhero committed
979 980 981 982 983
        const auto& sym = symbols[++m_index];
        if (m_mask.empty() || fnmatch(m_mask, sym.first))
        {
            return true;
        }
ussrhero's avatar
ussrhero committed
984 985
    }

ussrhero's avatar
ussrhero committed
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
    return false;
}
///////////////////////////////////////////////////////////////////////////////

std::wstring SymbolEnumeratorClang::getName()
{
    return strToWStr(m_symbolProvider->m_symbols[m_index].first);
}

///////////////////////////////////////////////////////////////////////////////

MEMOFFSET_64 SymbolEnumeratorClang::getOffset()
{
    return 0;
}

///////////////////////////////////////////////////////////////////////////////

TypeInfoPtr SymbolEnumeratorClang::getType()
{
    return TypeInfoPtr(new TypeInfoClangFunc(m_symbolProvider->m_astSession, m_symbolProvider->m_symbols[m_index].second));
1007 1008 1009 1010
}

///////////////////////////////////////////////////////////////////////////////

ussrhero's avatar
ussrhero committed
1011
SymbolProviderPtr getSymbolProviderFromSource(const std::wstring& source, const std::wstring&  opts)
1012
{
ussrhero's avatar
ussrhero committed
1013
    return SymbolProviderPtr( new SymbolProviderClang(wstrToStr(source), wstrToStr(opts) ) );
1014 1015 1016 1017
}

///////////////////////////////////////////////////////////////////////////////

ussrhero's avatar
ussrhero committed
1018
SymbolProviderPtr getSymbolProviderFromSource(const std::string& source, const std::string&  opts)
1019
{
ussrhero's avatar
ussrhero committed
1020
    return SymbolProviderPtr(new SymbolProviderClang(source, opts));
1021 1022 1023
}

///////////////////////////////////////////////////////////////////////////////
SND\ussrhero_cp's avatar
 
SND\ussrhero_cp committed
1024 1025
}