static void show_entry(tagEntry *entry) { const gchar *kind; const gchar *signature; const gchar *scope; const gchar *file; const gchar *name; gchar *scope_str; gchar *kind_str; file = entry->file; if (!file) file = ""; name = entry->name; if (!name) name = ""; signature = tagsField(entry, "signature"); if (!signature) signature = ""; scope = tagsField(entry, "class"); if (!scope) scope = tagsField(entry, "struct"); if (!scope) scope = tagsField(entry, "union"); if (!scope) scope = tagsField(entry, "enum"); if (scope) scope_str = g_strconcat(scope, "::", NULL); else scope_str = g_strdup(""); kind = entry->kind; if (kind) { kind_str = g_strconcat(kind, ": ", NULL); SETPTR(kind_str, g_strdup_printf("%-14s", kind_str)); } else kind_str = g_strdup(""); msgwin_msg_add(COLOR_BLACK, -1, NULL, "%s:%lu:\n %s%s%s%s", file, entry->address.lineNumber, kind_str, scope_str, name, signature); g_free(scope_str); g_free(kind_str); }
bool Parse::getScopeAndLocals(Scope * sc, const QString &expr, const QString &ident) { // initialize scope if nothing better is found sc->scope = ""; sc->localdef = ""; /* create a tags file for `expr' with function names only. * The function with the highest line number is our valid scope * --sort=no, because tags generation probably faster, and * so I just have to look for the last entry to find 'my' tag */ QString command = ctagsCmdPath + " --language-force=c++ --sort=no --fields=fKmnsz --c++-kinds=fn -o \"" + smallTagsFilePath + "\" \"" + parsedFilePath + '\"'; // I don't process any user input, so system() should be safe enough QProcess ctags; ctags.execute(command); QFile::remove (parsedFilePath); if (ctags.exitStatus() == QProcess::CrashExit) return false; /* find the last entry, this is our current scope */ tagFileInfo info; tagFile *tfile = tagsOpen(smallTagsFilePath.toAscii(), &info); tagEntry entry; const char *scope = NULL; if (tfile && info.status.opened) { if (tagsFirst(tfile, &entry) == TagSuccess) { do scope = tagsField(&entry, "class"); while (tagsNext(tfile, &entry) == TagSuccess); } tagsClose(tfile); } /* must be before the 'type = extract_type_qualifier()' code, which modifies scope */ if (scope) sc->scope = scope; /* get local definition (if any) */ if (ident!="") { QString type = extractTypeQualifier(expr, ident); if (type.length()) { sc->localdef = type; } else sc->localdef = ""; } QFile::remove (smallTagsFilePath); return true; }
QString Parse::getTypeOfToken(const QString &ident, const QString &className, Scope * scope, bool token_is_function) { /* if we have a variable and already found a local definition, just return it after duplicating */ if (!token_is_function && scope->localdef.length()) return scope->localdef; /* if the identifier is this-> return the current class */ if (ident == "this") return scope->scope; Tree *tree = NULL; if (className.length()) { tree = Tree::buildInheritanceTree(className); if (!tree) return NULL; } tagFileInfo info; tagEntry entry; tagFile *tfile = tagsOpen(tagsFilePath.toAscii(), &info); if (tfile && info.status.opened) { if (tagsFind(tfile, &entry, ident.toAscii(), TAG_OBSERVECASE | TAG_FULLMATCH) == TagSuccess) { do { if (tree && !tree->isMemberOfScope(&entry, scope)) continue; const char *kind = tagsField(&entry, "kind"); if (token_is_function) /* only list if tag is a function */ { if (!kind || (strcmp(kind, "function") && strcmp(kind, "prototype"))) continue; } else /* or a variable */ { //brc: add externvar for extern variables like cout if (!kind || (strcmp(kind, "variable") && strcmp(kind, "externvar") //brc: namespace workarround: add namespace && strcmp(kind, "namespace") && strcmp(kind, "member"))) continue; } /* need to duplicate the pattern, don't ask me why */ QString type = extractTypeQualifier(entry.address.pattern, ident); if(tree) tree->freeTree(); tagsClose(tfile); return type; } while (tagsFindNext(tfile, &entry) == TagSuccess); } tagsClose(tfile); } return NULL; }
Tag Parse::prettifyTag(const tagEntry * entry) { const char *signature = tagsField(entry, "signature"); const char *kind = tagsField(entry, "kind"); const char *access = tagsField(entry, "access"); Tag tag; tag.isFunction = signature; tag.name = entry->name; char *p = (char *) entry->address.pattern; /* for a macro the pattern is already parsed */ if (!strcmp(kind, "macro")) { /* NOTE: exuberant-ctags 5.5.4 does not provide a valid pattern for found macros * work around it, by getting the line myself */ char pat_macro[512]; unsigned long line = entry->address.lineNumber; if (line == 0) /* sometimes ctags can't find the correct line */ return tag; FILE *fileMacro = fopen(entry->file, "r"); if (fileMacro) { while ((p = fgets(pat_macro, 512, fileMacro)) != NULL) { line--; if (line <= 0) { /* remove leading spaces */ p++; /* skip over # - it is added later again */ while (*p == ' ' || *p == '\t') p++; tag.longName = '#' + p; /* remove new line at the end */ tag.longName.remove(tag.longName.length() - 1, 1); break; } } tag.longName += " [macro]"; fclose(fileMacro); return tag; } } /* special handling for enumerator */ if (!strcmp(kind, "enumerator")) { /* skip whitespace from variable/function patterns */ size_t skip = strspn(p, "/^ \t"); p += skip; /* remove trailing $/ characters */ char *pos = NULL; if ((pos = strstr(p, "$/")) != NULL) *pos = '\0'; /* replace \/\/ and \/ * *\/ to correctly show comments */ while ((pos = strstr(p, "\\/\\/")) != NULL) memcpy(pos, " //", 4); while ((pos = strstr(p, "\\/*")) != NULL) memcpy(pos, " /*", 3); while ((pos = strstr(p, "*\\/")) != NULL) memcpy(pos, " */", 3); tag.longName += QString(p) + " [enumerator]"; return tag; } size_t skip = strspn(p, "/^ \t"); p += skip; /* remove trailing $/ characters */ char *pos = NULL; if ((pos = strstr(p, "$/")) != NULL) *pos = '\0'; tag.longName += p; /* if it is a function, add signature as well */ if (signature) tag.parameters += signature; if (access && (!strcmp(access, "private") || !strcmp(access, "protected"))) tag.longName += '[' + access + ']'; return tag; }