📄 tree.cpp
字号:
/******************************************************************************************************** * PROGRAM : * DATE - TIME : lundi 10 avril 2006 - 22:28 * AUTHOR : IComplete Team and Anacr0x ( fred.julian at gmail.com ) * FILENAME : * LICENSE : GPL * COMMENTARY : Modified file (with qt) of the icomplete project ********************************************************************************************************/#include <QRegExp>#include "tree.h"#include "parse.h"#include "readtags.h"InitCompletion* Tree::parent = NULL;//brc: new subroutinevoid Tree::addTreeChild(const QString &className){ /* check this class if not already in the tree to * avoid a hangup with a broken (=cirular) tags file */ if (findInTree(className) == NOT_FOUND) { Tree *child = Tree::buildInheritanceTree(className); inherits << child; }}Tree* Tree::buildInheritanceTree(const QString &className){ Tree *root = new Tree; root->name = className; tagEntry entry; tagFileInfo info; tagFile *tfile = tagsOpen(parent->tagsFilePath.toAscii(), &info); //brc: split namespace part and classname char nbuffer[256]; char *nspace = NULL; strncpy(nbuffer, className.toAscii(), 256); nbuffer[255] = '\0'; char *cname = nbuffer; char *p = nbuffer; char *np = NULL; while ((np = strstr(p, "::"))) p = np + 2; if (p != nbuffer) { *(p - 2) = '\0'; nspace = nbuffer; cname = p; } Tree *tree = root; //brc: namespace workaround: if no namespace is present, try to find the class // also in std:: if (!nspace) { char buffer[512]; strcpy(buffer, "std::"); strcat(buffer, cname); tree->addTreeChild(buffer); } int i = 0; // counters if (tfile && info.status.opened) { if (tagsFind(tfile, &entry, cname, TAG_OBSERVECASE | TAG_FULLMATCH) == TagSuccess) { do { //brc:follow typedefs ... if (!strcmp(entry.kind, "typedef") && entry.address.pattern) { const char *field_namespace = tagsField(&entry, "namespace"); if ((nspace && field_namespace && !strcmp(field_namespace, nspace)) || !nspace) { char pattern[256]; strncpy(pattern, entry.address.pattern, 256); pattern[255] = '\0'; char *p = strstr(pattern, "typedef"); if (p && strstr(pattern, cname)) { p += strlen("typedef"); char *p1; if ((p1 = strstr(p, "typename"))) p = p1 + strlen("typename"); if (strstr(p, "struct")) continue; if ((p = strtok(p, " \n\t<"))) { tree->freeTree(); if (nspace) { char buffer[512]; strcpy(buffer, nspace); strcat(buffer, "::"); strcat(buffer, p); return Tree::buildInheritanceTree(buffer); } else { return Tree::buildInheritanceTree(p); } } } } } /* need to get the entry for the class definition */ if (!strcmp(entry.kind, "class") || !strcmp(entry.kind, "struct") || !strcmp(entry.kind, "union")) { /* and look for the entry "inherits" to see which are superclassNamees of className */ for (; i < entry.fields.count; i++) { if (!strcmp(entry.fields.list[i].key, "inherits")) { /* split the inherits string to single classNamees for multiple inheritance */ char *allinherits = strdup(entry.fields.list[i].value); char *buffer = NULL; char *inherit = strtok(allinherits, ","); while (inherit != NULL) { tree->addTreeChild(inherit); /* next token */ inherit = strtok(buffer, ","); } free(allinherits); goto end; } } // no more superclassNamees goto end; } } while (tagsFindNext(tfile, &entry)); }end: tagsClose(tfile); } return root;}void Tree::freeTree(){ for (int i = 0; i < inherits.size(); i++) inherits[i]->freeTree();}Match Tree::findInTree(const QString &className){ if ( name == className) return DIRECT_HIT; for (int i = 0; i < inherits.size(); i++) if (inherits[i]->findInTree(className) >= DIRECT_HIT) return SUBCLASS; return NOT_FOUND;}bool Tree::isMemberOfScope(const tagEntry * entry, const Scope * scope){ const char *field_className = tagsField(entry, "class"); const char *field_struct = tagsField(entry, "struct"); const char *field_union = tagsField(entry, "union"); //const char *field_namespace = tagsField(entry, "namespace"); const char *field_access = tagsField(entry, "access"); const char *tag_className = NULL; if (field_className) tag_className = field_className; else if (field_struct) tag_className = field_struct; else if (field_union) tag_className = field_union; else return false; /* tag must be part of (inherited) className to show it */ Match match_tag = findInTree(tag_className); if (match_tag == NOT_FOUND) return false; if (field_union) return true; if (!field_access) return false; if (!strcmp(field_access, "public")) return true; /* if access is not public, current scope must be in one of the * (inherited) classNamees */ Match match_curscope = findInTree(scope->scope); if (!strcmp(field_access, "protected") && match_curscope >= DIRECT_HIT) return true; else if (!strcmp(field_access, "private") && match_curscope == DIRECT_HIT) return true; return false;}TagList Tree::findEntries(const Expression * exp, const Scope * scope){ QList < Tag > TagList; tagEntry entry; tagFileInfo info; tagFile *tfile = tagsOpen(parent->tagsFilePath.toAscii(), &info); char lasttag[256] = ""; /* store last tag to avoid duplicates */ /* create an inheritance tree of our class or current scope, depending what we want to complete */ Tree *tree = NULL; if (exp->access & AccessMembers || exp->access & AccessPointer || exp->access & AccessStatic || exp->access & AccessInFunction) tree = Tree::buildInheritanceTree(exp->className); else if (exp->access & AccessGlobal) tree = Tree::buildInheritanceTree(scope->scope); if (!tree) { printf("Couldn't build inheritance tree\n"); return QList < Tag > (); } /* parse the tags file */ if (tfile && info.status.opened) { /* we can do a binary search for function definitions */ if (exp->access == AccessInFunction && tagsFind(tfile, &entry, exp->function.toAscii(), TAG_FULLMATCH | TAG_OBSERVECASE) == TagSuccess) { do { bool show_this_tag = false; const char *field_kind = tagsField(&entry, "kind"); if (field_kind && (!strcmp(field_kind, "member") || !strcmp(field_kind, "method"))) show_this_tag = tree->isMemberOfScope(&entry, scope); else if (!strcmp(field_kind, "function") || !strcmp(field_kind, "prototype")) { if (exp->className == "") // only a function, not method of a class show_this_tag = true; else show_this_tag = tree->isMemberOfScope(&entry, scope); } if (!show_this_tag) continue; /* output the tag if it is valid and no duplicate either to stdout * or to a file if the -o flag was given */ Tag tag; tag = Parse::prettifyTag(&entry); if ( ( exp->writing.length() && exp->writing[0] == 0 ) || tag.name.startsWith(exp->writing)) TagList << tag; } while (tagsFindNext(tfile, &entry) == TagSuccess); } // otherwise loop through all tags // and filter those which match one of our inherited class names else if (tagsFirst(tfile, &entry) == TagSuccess) { do { bool show_this_tag = false; const char *field_kind = tagsField(&entry, "kind"); const char *field_className = tagsField(&entry, "class"); const char *field_struct = tagsField(&entry, "struct"); const char *field_union = tagsField(&entry, "union"); const char *field_namespace = tagsField(&entry, "namespace"); const char *field_access = tagsField(&entry, "access"); switch (exp->access) { /* * find MEMBERS of classes/structs */ case AccessMembers: case AccessPointer: if (strstr(entry.address.pattern, "static ")) continue; /* Qt 3 defines this, and checking for it does not harm other users */ if (strstr(entry.address.pattern, "QT_STATIC_CONST ")) continue; // don't show destructors, can't call them directly anyways. if ( QString(entry.name).length() && entry.name[0] == '~') { show_this_tag = false; break; } // TODO: namespace support if (field_kind && (!strcmp(field_kind, "member") || !strcmp(field_kind, "function") || !strcmp(field_kind, "prototype") || !strcmp(field_kind, "method"))) show_this_tag = tree->isMemberOfScope(&entry, scope); break; /* * find STATIC functions/variables (everything after a ::) */ case AccessStatic: /* when we find a tag, the following conditions must be met, to show the tag: * - must be part of a className or namespace * - must contain "static" on the line * - must be "public" */ if (field_className) { if (exp->className == QString(field_className) && field_access && !strcmp(field_access, "public")) /* XXX: Workaround ctags limitation and try to find out * ourselves, if this tag is a static one, if it * has "static" in the pattern */ if (strstr(entry.address.pattern, "static ") || strstr(entry.address.pattern, "QT_STATIC_CONST ")) show_this_tag = true; } else if (field_namespace) if (exp->className == QString(field_namespace)) show_this_tag = true; break; // find GLOBAL functions/variables/defines case AccessGlobal: // everthing which is not part of a className or struct matches if (!field_className && !field_struct && !field_union) show_this_tag = true; else // also show locals of current scope show_this_tag = tree->isMemberOfScope(&entry, scope); break; default: // things like if() while() for(), etc. break; } /* output the tag if it is valid and no duplicate either to stdout * or to a file if the -o flag was given */ if (show_this_tag ) { Tag tag; if (exp->access & AccessInFunction) tag = Parse::prettifyTag(&entry); else { strncpy(lasttag, entry.name, 256); tag = Parse::prettifyTag(&entry); } if ( ( exp->writing.length() && exp->writing[0] == 0 ) || tag.name.startsWith(exp->writing)) { TagList << tag; } } } while (tagsNext(tfile, &entry) == TagSuccess); } tagsClose(tfile); } else return QList < Tag > (); tree->freeTree(); return TagList;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -