#include "compiler/CBrowse.h" #include "compiler/CDecl.h" #include "compiler/CError.h" #include "compiler/CMangler.h" #include "compiler/CParser.h" #include "compiler/CPrep.h" #include "compiler/CompilerTools.h" #include "compiler/Unmangle.h" #include "compiler/objects.h" #include "compiler/templates.h" #include "cos.h" #include "plugin.h" Boolean gUseTokenStreamSource; Boolean gForceSourceLoc; Boolean gUseNameTable; static GList gBrowseData; static GList gClassData; static GList gMemberFuncList; static int gNextMemberFuncID; enum ELanguage { langUnknown, langC, langCPlus, langPascal, langObjectPascal, langJava, langAssembler, langFortran, langRez }; enum EBrowserItem { browseFunction, browseGlobal, browseClass, browseMacro, browseEnum, browseTypedef, browseConstant, browseTemplate, browsePackage, browseCompSymbolStart = 0x70, browseEnd = 0xFF }; enum { kAbstract = 1, kStatic = 2, kFinal = 4, kMember = 8, kInterface = 0x80, kPublic = 0x100, kInline = 0x80, kPascal = 0x100, kAsm = 0x200, kVirtual = 0x400, kCtor = 0x800, kDtor = 0x1000, kNative = 0x2000, kSynch = 0x4000, kIntrinsic = 0x8000, kConst = 0x10000, kTransient = 0x80, kVolatile = 0x100 }; enum EAccess { accessNone = 0, accessPrivate = 1, accessProtected = 2, accessPublic = 4 }; enum EMember { memberFunction, memberData, memberEnd = 0xFF }; enum ETemplateType { templateClass, templateFunction }; static enum EAccess gFromAccessType[] = { accessPublic, accessPrivate, accessProtected, accessNone }; typedef struct BrowseHeader { SInt32 browse_header; SInt32 browse_version; SInt16 browse_language; SInt16 uses_name_table; SInt32 earliest_compatible_version; SInt32 reserved[15]; } BrowseHeader; // forward decls static void RecordUndefinedMemberFunctions(void); void CBrowse_Setup(CompilerLinkerParamBlk *params) { BrowseHeader hdr; CError_ASSERT(123, params != NULL); params->object.browsedata = NULL; InitGList(&gBrowseData, 0x10000); InitGList(&gMemberFuncList, 1024); gNextMemberFuncID = 1; gForceSourceLoc = 0; gUseNameTable = 0; memclrw(&hdr, sizeof(hdr)); hdr.browse_header = 0xBEABBAEB; hdr.browse_version = 2; hdr.earliest_compatible_version = 2; hdr.browse_language = copts.cplusplus ? langCPlus : langC; hdr.uses_name_table = gUseNameTable; AppendGListData(&gBrowseData, &hdr, sizeof(hdr)); } void CBrowse_Finish(CompilerLinkerParamBlk *params) { CWMemHandle hnd; CError_ASSERT(151, params != NULL); if (gBrowseData.size >= sizeof(BrowseHeader)) { RecordUndefinedMemberFunctions(); AppendGListByte(&gBrowseData, -1); COS_ResizeHandle(gBrowseData.data, gBrowseData.size); if (CWSecretAttachHandle(params->context, gBrowseData.data, &hnd) == cwNoErr) { params->object.browsedata = hnd; gBrowseData.data = NULL; } } } void CBrowse_Cleanup(CompilerLinkerParamBlk *params) { FreeGList(&gBrowseData); FreeGList(&gClassData); FreeGList(&gMemberFuncList); } static void AppendGList(GList *dst, GList *src) { SInt32 offset = dst->size; AppendGListNoData(dst, src->size); memcpy(*dst->data + offset, *src->data, src->size); } static void RecordName(GList *gl, const char *str, SInt32 id) { HashNameNode *name; CError_ASSERT(190, gl && str && *str); if (id < 0 && gUseNameTable) { for (name = name_hash_nodes[CHash(str)]; name; name = name->next) { if (!strcmp(str, name->name)) { id = name->id; break; } } } if (id >= 0 && gUseNameTable) { AppendGListWord(gl, -1); AppendGListLong(gl, id); } else { int len = strlen(str); AppendGListWord(gl, len); if (len) AppendGListData(gl, str, len + 1); } } void CBrowse_BeginClass(DeclInfo *di, GList *gl) { char *buf; ClassList *base; SInt32 i; TypeClass *tclass; CError_ASSERT(227, di && di->thetype && gl); *gl = gClassData; if ( !di->file || !di->file->fileID || !di->file->recordbrowseinfo || !di->file2 || !di->file2->fileID || di->x60 <= 0 ) { memclrw(&gClassData, sizeof(gClassData)); return; } if (IsTempName(TYPE_CLASS(di->thetype)->classname)) { memclrw(&gClassData, sizeof(gClassData)); return; } InitGList(&gClassData, 0x4000); AppendGListByte(&gClassData, browseClass); AppendGListWord(&gClassData, di->file->fileID); AppendGListWord(&gClassData, di->file2->fileID); AppendGListLong(&gClassData, di->x60 - 1); CError_ASSERT(270, gClassData.size == 9); AppendGListLong(&gClassData, di->x60 - 1); AppendGListLong(&gClassData, 0); RecordName(&gClassData, TYPE_CLASS(di->thetype)->classname->name, TYPE_CLASS(di->thetype)->classname->id); CMangler_MangleType(di->thetype, 0); AppendGListByte(&name_mangle_list, 0); buf = lalloc(name_mangle_list.size + 1); strcpy(buf, *name_mangle_list.data); while (*buf && *buf >= '0' && *buf <= '9') buf++; if (strcmp(TYPE_CLASS(di->thetype)->classname->name, buf)) RecordName(&gClassData, buf, -1); else AppendGListWord(&gClassData, 0); AppendGListLong(&gClassData, 0); i = 0; base = TYPE_CLASS(di->thetype)->bases; while (base) { base = base->next; i++; } AppendGListByte(&gClassData, i); for (base = TYPE_CLASS(di->thetype)->bases; base; base = base->next) { AppendGListByte(&gClassData, gFromAccessType[base->access]); AppendGListByte(&gClassData, base->is_virtual); tclass = base->base; if ((tclass->flags & CLASS_FLAGS_800) && !TEMPL_CLASS_INST(tclass)->is_specialized) tclass = TYPE_CLASS(TEMPL_CLASS_INST(tclass)->templ); CMangler_MangleType(TYPE(tclass), 0); AppendGListByte(&name_mangle_list, 0); buf = lalloc(name_mangle_list.size + 1); strcpy(buf, *name_mangle_list.data); while (*buf && *buf >= '0' && *buf <= '9') buf++; i = base->base->classname->id; while (*buf && *buf >= '0' && *buf <= '9') { i = -1; buf++; } RecordName(&gClassData, buf, i); } } void CBrowse_AddClassMemberVar(ObjMemberVar *ivar, SInt32 startOffset, SInt32 endOffset) { short len; CError_ASSERT(360, ivar); if (gClassData.data && startOffset > 0 && endOffset >= startOffset) { if (tk == ';') endOffset++; AppendGListByte(&gClassData, memberData); AppendGListByte(&gClassData, gFromAccessType[ivar->access]); AppendGListLong(&gClassData, 0); AppendGListLong(&gClassData, startOffset - 1); AppendGListLong(&gClassData, endOffset - 1); len = strlen(ivar->name->name); AppendGListWord(&gClassData, len); AppendGListData(&gClassData, ivar->name->name, len + 1); } } void CBrowse_AddClassMemberFunction(Object *object, SInt32 startOffset, SInt32 endOffset) { SInt32 flags; SInt32 id; TypeMethod *tfunc; CError_ASSERT(380, object); if ( !IsTempName(object->name) && gClassData.data && startOffset > 0 && endOffset >= startOffset ) { flags = 0; CError_ASSERT(391, object->type && IS_TYPE_FUNC(object->type)); tfunc = TYPE_METHOD(object->type); if (tfunc->flags & FUNC_FLAGS_100) return; if (object->datatype == DVFUNC) flags |= kVirtual; if (tfunc->flags & FUNC_FLAGS_8) flags |= kAbstract; if (tfunc->x26) flags |= kStatic; if (tfunc->flags & FUNC_FLAGS_1000) flags |= kCtor; if (tfunc->flags & FUNC_FLAGS_2000) flags |= kDtor; AppendGListByte(&gClassData, memberFunction); AppendGListByte(&gClassData, gFromAccessType[object->access]); AppendGListLong(&gClassData, flags); id = tfunc->x22; if (id <= 0) { // TODO: this is not 64-bit safe if (!(tfunc->flags & FUNC_FLAGS_2) || id == -1) AppendGListLong(&gMemberFuncList, (SInt32) object); tfunc->x22 = id = gNextMemberFuncID++; } AppendGListLong(&gClassData, id); AppendGListLong(&gClassData, startOffset - 1); AppendGListLong(&gClassData, endOffset); } } void CBrowse_AddClassMemberData(Object *object, SInt32 startOffset, SInt32 endOffset) { short len; CError_ASSERT(435, object); if (gClassData.data && startOffset > 0 && endOffset >= startOffset && object->datatype == DDATA) { if (tk == ';') endOffset++; AppendGListByte(&gClassData, memberData); AppendGListByte(&gClassData, gFromAccessType[object->access]); AppendGListLong(&gClassData, kStatic); AppendGListLong(&gClassData, startOffset - 1); AppendGListLong(&gClassData, endOffset - 1); len = strlen(object->name->name); AppendGListWord(&gClassData, len); AppendGListData(&gClassData, object->name->name, len + 1); } } void CBrowse_EndClass(SInt32 offset, GList *gl) { CError_ASSERT(453, gl); if (gClassData.data) { if (gClassData.size > 0) { if (tk == ';') offset++; memcpy(*gClassData.data + 9, &offset, 4); AppendGList(&gBrowseData, &gClassData); AppendGListByte(&gBrowseData, memberEnd); } FreeGList(&gClassData); } gClassData = *gl; } void CBrowse_BeginStruct(DeclInfo *di, TypeStruct *tstruct, GList *gl) { HashNameNode *name; CError_ASSERT(480, di && gl); *gl = gClassData; if ( !di->file || !di->file->fileID || !di->file->recordbrowseinfo || !di->file2 || !di->file2->fileID || di->x60 <= 0 ) { memclrw(&gClassData, sizeof(gClassData)); return; } name = tstruct->name; if (!name || IsTempName(name)) { memclrw(&gClassData, sizeof(gClassData)); return; } InitGList(&gClassData, 0x4000); AppendGListByte(&gClassData, browseClass); AppendGListWord(&gClassData, di->file->fileID); AppendGListWord(&gClassData, di->file2->fileID); AppendGListLong(&gClassData, di->x60 - 1); CError_ASSERT(521, gClassData.size == 9); AppendGListLong(&gClassData, di->x60 - 1); AppendGListLong(&gClassData, 0); RecordName(&gClassData, name->name, name->id); AppendGListWord(&gClassData, 0); AppendGListLong(&gClassData, 0); AppendGListByte(&gClassData, 0); } void CBrowse_AddStructMember(StructMember *member, SInt32 startOffset, SInt32 endOffset) { short len; if (tk == ';') endOffset++; if (gClassData.data && member && startOffset > 0 && endOffset >= startOffset) { AppendGListByte(&gClassData, memberData); AppendGListByte(&gClassData, accessPublic); AppendGListLong(&gClassData, 0); AppendGListLong(&gClassData, startOffset - 1); AppendGListLong(&gClassData, endOffset - 1); len = strlen(member->name->name); AppendGListWord(&gClassData, len); AppendGListData(&gClassData, member->name->name, len + 1); } } void CBrowse_EndStruct(SInt32 offset, GList *gl) { CError_ASSERT(558, gl); if (gClassData.data) { if (offset > 0 && gClassData.size > 0) { memcpy(*gClassData.data + 9, &offset, 4); AppendGList(&gBrowseData, &gClassData); AppendGListByte(&gBrowseData, memberEnd); } FreeGList(&gClassData); } gClassData = *gl; } static void EmitStandardData(int item, int fileID1, int fileID2, SInt32 startOffset, SInt32 endOffset, const char *str, SInt32 id, const char *str2, SInt32 id2) { CError_ASSERT(584, str); AppendGListByte(&gBrowseData, item); AppendGListWord(&gBrowseData, fileID1); AppendGListWord(&gBrowseData, fileID2); AppendGListLong(&gBrowseData, startOffset - 1); AppendGListLong(&gBrowseData, endOffset - 1); AppendGListLong(&gBrowseData, 0); RecordName(&gBrowseData, str, id); if (str2 && str2 != str) RecordName(&gBrowseData, str2, id2); else AppendGListWord(&gBrowseData, 0); } void CBrowse_NewTypedef(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { CError_ASSERT(618, file1 && file1->recordbrowseinfo); if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { EmitStandardData(browseTypedef, file1->fileID, file2->fileID, startOffset, endOffset, name->name, name->id, CError_GetQualifiedName(nspace, name), -1); } } void CBrowse_NewEnum(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { CError_ASSERT(632, file1 && file1->recordbrowseinfo); if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { EmitStandardData(browseEnum, file1->fileID, file2->fileID, startOffset, endOffset, name->name, name->id, CError_GetQualifiedName(nspace, name), -1); } } void CBrowse_NewEnumConstant(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { CError_ASSERT(646, file1 && file1->recordbrowseinfo); if (tk == ',') endOffset++; if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { EmitStandardData(browseConstant, file1->fileID, file2->fileID, startOffset, endOffset, name->name, name->id, CError_GetQualifiedName(nspace, name), -1); } } static HashNameNode *CBrowse_GetLinkName(Object *object) { return CMangler_GetLinkName(object); } static void RecordFunction(Object *object, int fileID1, int fileID2, SInt32 startOffset, SInt32 endOffset) { TypeFunc *tfunc; char *tmp; Boolean flag; char *str29; HashNameNode *linkname; SInt32 flags; char *namestr; SInt32 nameid; char *namestr2; SInt32 nameid2; int funcid; char buf[2048]; char buf2[256]; CError_ASSERT(740, object->type && IS_TYPE_FUNC(object->type)); if (IsTempName(object->name)) return; tfunc = TYPE_FUNC(object->type); if ((tfunc->flags & (FUNC_FLAGS_100 | FUNC_FLAGS_200)) && (!fileID2 || startOffset < 0)) return; linkname = object->name; tmp = linkname->name; if (!(linkname->name[0] == '_' && linkname->name[1] == '_')) { namestr = tmp; nameid = linkname->id; switch (tmp[0]) { case '.': nameid = -1; namestr += 1; break; case '_': switch (tmp[1]) { case '#': case '%': case '@': nameid = -1; namestr += 2; break; } break; } } else { flag = 1; if (tfunc->flags & (FUNC_FLAGS_1000 | FUNC_FLAGS_2000)) { tmp = TYPE_METHOD(tfunc)->theclass->classname->name; while (*tmp >= '0' && *tmp <= '9') tmp++; MWUnmangleClassName(tmp, buf, sizeof(buf)); str29 = buf; if ((tmp = strrchr(str29, ':'))) str29 = tmp + 1; if (tfunc->flags & FUNC_FLAGS_2000) { buf2[0] = '~'; strncpy(&buf2[1], str29, sizeof(buf2) - 1); namestr = buf2; } else { namestr = str29; } flag = 0; } if (flag) { MWUnmangle(object->name->name, buf, sizeof(buf)); namestr = buf; } nameid = -1; } while (*namestr >= '0' && *namestr <= '9') { nameid = -1; namestr++; } namestr2 = NULL; nameid2 = -1; linkname = CBrowse_GetLinkName(object); if (object->name != linkname) { namestr2 = linkname->name; if (linkname->name[0] == '.') namestr2++; else nameid2 = linkname->id; } EmitStandardData(browseFunction, fileID1, fileID2, startOffset, endOffset, namestr, nameid, namestr2, nameid2); flags = 0; if (object->qual & Q_INLINE) flags |= kInline; if (object->qual & Q_PASCAL) flags |= kPascal; if (object->qual & Q_ASM) flags |= kAsm; if (object->sclass == TK_STATIC) flags |= kStatic; if (tfunc->flags & FUNC_FLAGS_METHOD) flags |= kMember; AppendGListLong(&gBrowseData, flags); funcid = 0; if (tfunc->flags & FUNC_FLAGS_METHOD) { funcid = TYPE_METHOD(tfunc)->x22; if (funcid <= 0) { TYPE_METHOD(tfunc)->x22 = funcid = gNextMemberFuncID++; } } AppendGListLong(&gBrowseData, funcid); } void CBrowse_NewFunction(Object *object, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { CError_ASSERT(890, file1 && file1->recordbrowseinfo); if (file2 && file2->fileID && startOffset > 0 && (endOffset + 1) >= startOffset) RecordFunction(object, file1->fileID, file2->fileID, startOffset, endOffset + 1); } void CBrowse_NewData(Object *object, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { char *namestr = NULL; SInt32 flags = 0; Boolean is_const = is_const_object(object); CError_ASSERT(912, file1 && file1->recordbrowseinfo); CError_ASSERT(913, object); if (tk == ';') endOffset++; if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { HashNameNode *name = CBrowse_GetLinkName(object); if (object->name != name) namestr = name->name; EmitStandardData( is_const ? browseConstant : browseGlobal, file1->fileID, file2->fileID, startOffset, endOffset, object->name->name, object->name->id, namestr, name->id ); if (!is_const) { if (object->sclass == TK_STATIC) flags |= kStatic; AppendGListLong(&gBrowseData, flags); } } } void CBrowse_NewMacro(Macro *macro, CPrepFileInfo *file, SInt32 startOffset, SInt32 endOffset) { CError_ASSERT(951, !file || (file->recordbrowseinfo && !macro->is_special)); if (file && file->fileID && startOffset > 0 && endOffset >= startOffset) EmitStandardData( browseMacro, file->fileID, file->fileID, startOffset, endOffset, macro->name->name, macro->name->id, NULL, -1 ); } void CBrowse_NewTemplateClass(TemplClass *tmclass, CPrepFileInfo *file, SInt32 startOffset, SInt32 endOffset) { CError_ASSERT(965, !file || file->recordbrowseinfo); if (file && file->fileID && startOffset > 0 && endOffset >= startOffset) { EmitStandardData( browseTemplate, file->fileID, file->fileID, startOffset, endOffset, tmclass->theclass.classname->name, tmclass->theclass.classname->id, NULL, -1 ); AppendGListByte(&gBrowseData, templateClass); } } void CBrowse_NewTemplateFunc(TemplateFunction *tmfunc) { CError_ASSERT(979, !tmfunc->srcfile || tmfunc->srcfile->recordbrowseinfo); if (tmfunc->srcfile && tmfunc->srcfile->fileID && tmfunc->startoffset > 0 && tmfunc->endoffset >= tmfunc->startoffset) { EmitStandardData( browseTemplate, tmfunc->srcfile->fileID, tmfunc->srcfile->fileID, tmfunc->startoffset, tmfunc->endoffset, tmfunc->name->name, tmfunc->name->id, NULL, -1 ); AppendGListByte(&gBrowseData, templateFunction); } } static void RecordUndefinedMemberFunctions(void) { int i; int count; Object **array; COS_LockHandleHi(gMemberFuncList.data); count = gMemberFuncList.size / sizeof(Object *); array = (Object **) *gMemberFuncList.data; for (i = 0; i < count; i++, array++) { if (IS_TYPE_FUNC((*array)->type) && !(TYPE_FUNC((*array)->type)->flags & FUNC_FLAGS_2)) RecordFunction(*array, 0, 0, -1, -1); } COS_UnlockHandle(gMemberFuncList.data); }