Esempio n. 1
0
bool QueryJob::locationToString(Location location,
                                const std::function<void(LocationPiece, const String &)> &cb,
                                Flags<WriteFlag> writeFlags)
{
    if (location.isNull())
        return false;
    Flags<Location::ToStringFlag> kf = locationToStringFlags();
    kf &= ~Location::ShowContext;
    cb(Piece_Location, location.toString(kf, &mContextCache));
    if (!(writeFlags & NoContext) && !(queryFlags() & QueryMessage::NoContext))
        cb(Piece_Context, location.context(kf, &mContextCache));

    const bool containingFunction = queryFlags() & QueryMessage::ContainingFunction;
    const bool containingFunctionLocation = queryFlags() & QueryMessage::ContainingFunctionLocation;
    const bool cursorKind = queryFlags() & QueryMessage::CursorKind;
    const bool displayName = queryFlags() & QueryMessage::DisplayName;
    if (containingFunction || containingFunctionLocation || cursorKind || displayName || !mKindFilters.isEmpty()) {
        int idx;
        Symbol symbol = project()->findSymbol(location, &idx);
        if (symbol.isNull()) {
            error() << "Somehow can't find" << location << "in symbols";
        } else {
            if (!mKindFilters.filter(symbol))
                return false;
            if (displayName)
                cb(Piece_SymbolName, symbol.displayName());
            if (cursorKind)
                cb(Piece_Kind, symbol.kindSpelling());
            if (containingFunction || containingFunctionLocation) {
                const uint32_t fileId = location.fileId();
                const unsigned int line = location.line();
                const unsigned int column = location.column();
                auto fileMap = project()->openSymbols(location.fileId());
                if (fileMap) {
                    while (idx > 0) {
                        symbol = fileMap->valueAt(--idx);
                        if (symbol.location.fileId() != fileId)
                            break;
                        if (symbol.isDefinition()
                            && RTags::isContainer(symbol.kind)
                            && comparePosition(line, column, symbol.startLine, symbol.startColumn) >= 0
                            && comparePosition(line, column, symbol.endLine, symbol.endColumn) <= 0) {
                            if (containingFunction)
                                cb(Piece_ContainingFunctionName, symbol.symbolName);
                            if (containingFunctionLocation)
                                cb(Piece_ContainingFunctionLocation, symbol.location.toString(locationToStringFlags() & ~Location::ShowContext));
                            break;
                        }
                    }
                }
            }
        }
    }
    return true;
}
Esempio n. 2
0
bool QueryJob::write(const Location &location, Flags<WriteFlag> flags)
{
    if (location.isNull())
        return false;
    if (!(flags & Unfiltered)) {
        if (!filterLocation(location))
            return false;
        flags |= Unfiltered;
    }
    String out = location.key(keyFlags());
    const bool containingFunction = queryFlags() & QueryMessage::ContainingFunction;
    const bool cursorKind = queryFlags() & QueryMessage::CursorKind;
    const bool displayName = queryFlags() & QueryMessage::DisplayName;
    if (containingFunction || cursorKind || displayName || !mKindFilters.isEmpty()) {
        int idx;
        Symbol symbol = project()->findSymbol(location, &idx);
        if (symbol.isNull()) {
            error() << "Somehow can't find" << location << "in symbols";
        } else {
            if (!filterKind(symbol.kind))
                return false;
            if (displayName)
                out += '\t' + symbol.displayName();
            if (cursorKind)
                out += '\t' + symbol.kindSpelling();
            if (containingFunction) {
                const uint32_t fileId = location.fileId();
                const unsigned int line = location.line();
                const unsigned int column = location.column();
                auto fileMap = project()->openSymbols(location.fileId());
                if (fileMap) {
                    while (idx > 0) {
                        symbol = fileMap->valueAt(--idx);
                        if (symbol.location.fileId() != fileId)
                            break;
                        if (symbol.isDefinition()
                            && RTags::isContainer(symbol.kind)
                            && comparePosition(line, column, symbol.startLine, symbol.startColumn) >= 0
                            && comparePosition(line, column, symbol.endLine, symbol.endColumn) <= 0) {
                            out += "\tfunction: " + symbol.symbolName;
                            break;
                        }
                    }
                }
            }
        }
    }
    return write(out, flags);
}
Esempio n. 3
0
int			checkCollisions( Game * game, Enemy ** enemies, Bullet ** bullets)
{
	int			i;
	int			j;
	Player		*player = game->getPlayer();;
	Bullet **	enemiesBullets;

	i = -1;
	comparePosition((Item *)player, (Item **)enemies, MAX_ENEMY);
	while ( ++i < MAX_ENEMY)
	{
		if (enemies[i])
		{
			comparePosition((Item *)enemies[i], (Item **)bullets, MAX_BULLETS);
			if (enemies[i]->canShoot())
			{
				enemiesBullets = enemies[i]->getBullets();
				comparePosition((Item*)player, (Item **)enemiesBullets, MAX_BULLETS);
				for ( j = 0; j < MAX_BULLETS; j++)
				{
					if (enemiesBullets[j]
						&& comparePosition( (Item *)enemiesBullets[j], (Item **)bullets, MAX_BULLETS) )
						{
							delete enemiesBullets[j];
							enemiesBullets[j] = NULL;
						}
				}
			}
			if ( enemies[i]->getHp() <= 0)
			{
				game->addKill();
				player->addScore(enemies[i]->getScorePoints());
				if (dynamic_cast<Boss *>(enemies[i]))
					return (1);
				delete enemies[i];
				enemies[i] = NULL;
			}
		}
	}
	return (0);
}
Esempio n. 4
0
int compare(const Block& b1, const Block& b2)
{
   if ( b1.getTypeId() > b2.getTypeId() ) {
      // Block b1's type id is greater than b2's type id
      return 1;
   }
   else if ( b1.getTypeId() < b2.getTypeId() ) {
      // Block b1's type id is less than b2's type id
      return -1;
   }
   else {
      // When block type ids are the same, then it's position
      return comparePosition(b1, b2);
   }
}
Esempio n. 5
0
String Symbol::toString(const std::shared_ptr<Project> &project,
                        const Flags<ToStringFlag> cursorInfoFlags,
                        Flags<Location::ToStringFlag> locationToStringFlags,
                        const Set<String> &pieceFilters) const
{
    auto filterPiece = [&pieceFilters](const char *name) { return pieceFilters.isEmpty() || pieceFilters.contains(name); };
    auto properties = [this, &filterPiece]() -> String {
        List<String> ret;
        if (isDefinition() && filterPiece("definition"))
            ret << "Definition";
        if (isContainer() && filterPiece("container"))
            ret << "Container";
        if ((flags & PureVirtualMethod) == PureVirtualMethod && filterPiece("purevirtual"))
            ret << "Pure Virtual";
        if (flags & VirtualMethod && filterPiece("virtual"))
            ret << "Virtual";

        if (flags & ConstMethod) {
            if (filterPiece("constmethod"))
                ret << "ConstMethod";
        } else if (flags & StaticMethod && filterPiece("static")) {
            ret << "Static";
        }

        if (flags & Variadic && filterPiece("variadic"))
            ret << "Variadic";
        if (flags & Auto && filterPiece("auto"))
            ret << "Auto";

        if (flags & MacroExpansion && filterPiece("macroexpansion"))
            ret << "MacroExpansion";
        if (flags & TemplateSpecialization && filterPiece("templatespecialization"))
            ret << "TemplateSpecialization";
        if (flags & TemplateReference && filterPiece("templatereference"))
            ret << "TemplateReference";

        if (ret.isEmpty())
            return String();
        return String::join(ret, ' ') + '\n';
    };

    List<String> bases;
    List<String> args;

    if (project) {
        if (filterPiece("baseclasses")) {
            for (const auto &base : baseClasses) {
                bool found = false;
                for (const auto &sym : project->findByUsr(base, location.fileId(), Project::ArgDependsOn)) {
                    bases << sym.symbolName;
                    found = true;
                    break;
                }
                if (!found) {
                    bases << base;
                }
            }
        }
        if (filterPiece("arguments")) {
            for (const auto &arg : arguments) {
                const String symName = project->findSymbol(arg.cursor).symbolName;
                if (!symName.isEmpty()) {
                    args << symName;
                } else {
                    args << arg.cursor.toString(locationToStringFlags & ~Location::ShowContext);
                }
            }
        }
    } else if (filterPiece("baseClasses")) {
        bases = baseClasses;
    }

    String ret;
    auto writePiece = [&ret, &filterPiece](const char *key, const char *filter, const String &piece) {
        if (piece.isEmpty())
            return;
        if (!filterPiece(filter))
            return;
        if (key && strlen(key))
            ret << key << ": ";
        ret << piece << "\n";
    };
    writePiece(0, "location", location.toString(locationToStringFlags));
    writePiece("SymbolName", "symbolname", symbolName);
    writePiece("Kind", "kind", kindSpelling());
    if (filterPiece("type")) {
        if (!typeName.isEmpty()) {
            ret += "Type: " + typeName + "\n";
        } else if (type != CXType_Invalid) {
            ret += "Type: " + RTags::eatString(clang_getTypeKindSpelling(type)) + "\n";
        }
    }
    writePiece("SymbolLength", "symbollength", std::to_string(symbolLength));

    if (startLine != -1)
        writePiece("Range", "range", String::format<32>("%d:%d-%d:%d", startLine, startColumn, endLine, endColumn));

#if CINDEX_VERSION_MINOR > 1
    if (kind == CXCursor_EnumConstantDecl)
        writePiece("Enum Value", "enumvalue",
                   String::format<32>("%lld/0x%0llx", static_cast<long long>(enumValue), static_cast<long long>(enumValue)));

    if (isDefinition() && RTags::isFunction(kind))
        writePiece("Stack cost", "stackcost", std::to_string(stackCost));
#endif
    writePiece(0, "linkage", linkageSpelling(linkage));
    ret += properties();
    writePiece("Usr", "usr", usr);
    if (size)
        writePiece("sizeof", "sizeof", std::to_string(size));
    if (fieldOffset >= 0)
        writePiece("Field offset (bits/bytes)", "fieldoffset",
                   String::format<32>("%d/%d", fieldOffset, fieldOffset / 8));
    if (alignment >= 0)
        writePiece("Alignment", "alignment", std::to_string(alignment));
    if (!args.isEmpty())
        writePiece("Arguments", "arguments", String::join(args, ", "));
    if (!bases.isEmpty())
        writePiece("Base classes", "baseclasses", String::join(bases, ", "));
    writePiece("Brief comment", "briefcomment", briefComment);
    writePiece("XML comment", "xmlcomment", xmlComment);

    if ((cursorInfoFlags & IncludeParents && filterPiece("parent"))
        || (cursorInfoFlags & (IncludeContainingFunction) && filterPiece("cf"))
        || (cursorInfoFlags & (IncludeContainingFunctionLocation) && filterPiece("cfl"))) {
        auto syms = project->openSymbols(location.fileId());
        uint32_t idx = -1;
        if (syms) {
            idx = syms->lowerBound(location);
            if (idx == std::numeric_limits<uint32_t>::max()) {
                idx = syms->count() - 1;
            }
        }
        const unsigned int line = location.line();
        const unsigned int column = location.column();
        while (idx-- > 0) {
            const Symbol s = syms->valueAt(idx);
            if (s.isDefinition()
                && s.isContainer()
                && comparePosition(line, column, s.startLine, s.startColumn) >= 0
                && comparePosition(line, column, s.endLine, s.endColumn) <= 0) {
                if (cursorInfoFlags & IncludeContainingFunctionLocation)
                    writePiece("Containing function location", "cfl", s.location.toString(locationToStringFlags));
                if (cursorInfoFlags & IncludeContainingFunction)
                    writePiece("Containing function", "cf", s.symbolName);
                if (cursorInfoFlags & IncludeParents)
                    writePiece("Parent", "parent", s.location.toString(locationToStringFlags)); // redundant, this is a mess
                break;
            }
        }
    }



    if (cursorInfoFlags & IncludeTargets && project && filterPiece("targets")) {
        const auto targets = project->findTargets(*this);
        if (targets.size()) {
            ret.append("Targets:\n");
            auto best = RTags::bestTarget(targets);
            ret.append(String::format<128>("    %s\n", best.location.toString(locationToStringFlags).constData()));

            for (const auto &tit : targets) {
                if (tit.location != best.location)
                    ret.append(String::format<128>("    %s\n", tit.location.toString(locationToStringFlags).constData()));
            }
        }
    }

    if (cursorInfoFlags & IncludeReferences && project && !isReference() && filterPiece("references")) {
        const auto references = project->findCallers(*this);
        if (references.size()) {
            ret.append("References:\n");
            for (const auto &r : references) {
                ret.append(String::format<128>("    %s\n", r.location.toString(locationToStringFlags).constData()));
            }
        }
    }

    return ret;
}
Esempio n. 6
0
Value Symbol::toValue(const std::shared_ptr<Project> &project,
                      Flags<ToStringFlag> toStringFlags,
                      Flags<Location::ToStringFlag> locationToStringFlags,
                      const Set<String> &pieceFilters) const
{
    auto filterPiece = [&pieceFilters](const char *name) { return pieceFilters.isEmpty() || pieceFilters.contains(name); };
    std::function<Value(const Symbol &, Flags<ToStringFlag>)> toValue = [&](const Symbol &symbol, Flags<ToStringFlag> f) {
        Value ret;
        auto formatLocation = [locationToStringFlags,&filterPiece, &ret](Location loc, const char *key, const char *ctxKey,
                                                                         const char *keyFilter = 0,
                                                                         const char *ctxKeyFilter = 0,
                                                                         Value *val = 0) {
            if (!val)
                val = &ret;
            if (filterPiece(keyFilter ? keyFilter : key))
                (*val)[key] = loc.toString(locationToStringFlags & ~Location::ShowContext);
            if (locationToStringFlags & Location::ShowContext && filterPiece(ctxKeyFilter ? ctxKeyFilter : ctxKey)) {
                (*val)[ctxKey] = loc.context(locationToStringFlags);
            }
        };
        if (!symbol.location.isNull()) {
            formatLocation(symbol.location, "location", "context");
        }
        if (!symbol.isNull()) {
            if (symbol.argumentUsage.index != String::npos) {
                formatLocation(symbol.argumentUsage.invocation, "invocation", "invocationContext", 0, "invocationcontext");
                if (filterPiece("invokedfunction"))
                    ret["invokedFunction"] = symbol.argumentUsage.invokedFunction.toString(locationToStringFlags);
                formatLocation(symbol.argumentUsage.argument.location, "functionArgumentLocation", "functionArgumentLocationContext",
                               "functionargumentlocation", "functionargumentlocationcontext");
                if (filterPiece("functionargumentcursor"))
                    ret["functionArgumentCursor"] = symbol.argumentUsage.argument.cursor.toString(locationToStringFlags);
                if (filterPiece("functionargumentlength"))
                    ret["functionArgumentLength"] = symbol.argumentUsage.argument.length;
                if (filterPiece("argumentindex"))
                    ret["argumentIndex"] = symbol.argumentUsage.index;
            }
            if (!symbol.symbolName.isEmpty() && filterPiece("symbolname"))
                ret["symbolName"] = symbol.symbolName;
            if (!symbol.usr.isEmpty() && filterPiece("usr"))
                ret["usr"] = symbol.usr;
            if (filterPiece("type")) {
                if (!symbol.typeName.isEmpty()) {
                    ret["type"] = symbol.typeName;
                } else if (symbol.type != CXType_Invalid) {
                    String str;
                    Log(&str) << symbol.type;
                    ret["type"] = str;
                }
            }

            if (!symbol.baseClasses.isEmpty() && filterPiece("baseclasses"))
                ret["baseClasses"] = symbol.baseClasses;
            if (!symbol.arguments.isEmpty() && filterPiece("arguments")) {
                Value args;
                for (const auto &arg : symbol.arguments) {
                    Value a;
                    formatLocation(arg.location, "location", "context", "arguments", "arguments", &a);
                    formatLocation(arg.location, "cursor", "cursorContext", "arguments", "arguments", &a);
                    a["length"] = arg.length;
                    args.push_back(a);
                }
                ret["arguments"] = args;
            }
            if (filterPiece("symbollength"))
                ret["symbolLength"] = symbol.symbolLength;
            if (filterPiece("kind")) {
                String str;
                Log(&str) << symbol.kind;
                ret["kind"] = str;
            }
            if (filterPiece("linkage")) {
                String str;
                Log(&str) << symbol.linkage;
                ret["linkage"] = str;
            }

            if (!symbol.briefComment.isEmpty() && filterPiece("briefcomment"))
                ret["briefComment"] = symbol.briefComment;
            if (!symbol.xmlComment.isEmpty() && filterPiece("xmlcomment"))
                ret["xmlComment"] = symbol.xmlComment;
            if (filterPiece("range")) {
                ret["startLine"] = symbol.startLine;
                ret["startColumn"] = symbol.startColumn;
                ret["endLine"] = symbol.endLine;
                ret["endColumn"] = symbol.endColumn;
            }
            if (symbol.size && filterPiece("sizeof"))
                ret["sizeof"] = symbol.size;
            if (symbol.fieldOffset >= 0 && filterPiece("fieldoffset"))
                ret["fieldOffset"] = symbol.fieldOffset;
            if (symbol.alignment >= 0 && filterPiece("alignment"))
                ret["alignment"] = symbol.alignment;
            if (symbol.kind == CXCursor_EnumConstantDecl && filterPiece("enumvalue"))
                ret["enumValue"] = symbol.enumValue;
            if (symbol.isDefinition()) {
                if (filterPiece("definition"))
                    ret["definition"] = true;
                if (RTags::isFunction(symbol.kind) && filterPiece("stackcost"))
                    ret["stackCost"] = symbol.stackCost;
            } else if (symbol.isReference() && filterPiece("reference")) {
                ret["reference"] = true;
            }
            if (symbol.isContainer() && filterPiece("container"))
                ret["container"] = true;
            if ((symbol.flags & Symbol::PureVirtualMethod) == Symbol::PureVirtualMethod && filterPiece("purevirtual"))
                ret["purevirtual"] = true;
            if (symbol.flags & Symbol::VirtualMethod && filterPiece("virtual"))
                ret["virtual"] = true;
            if (symbol.flags & Symbol::ConstMethod && filterPiece("constmethod"))
                ret["constmethod"] = true;
            if (symbol.flags & Symbol::StaticMethod && filterPiece("staticmethod"))
                ret["staticmethod"] = true;
            if (symbol.flags & Symbol::Variadic && filterPiece("variadic"))
                ret["variadic"] = true;
            if (symbol.flags & Symbol::Auto && filterPiece("auto"))
                ret["auto"] = true;
            if (symbol.flags & Symbol::MacroExpansion && filterPiece("macroexpansion"))
                ret["macroexpansion"] = true;
            if (symbol.flags & Symbol::TemplateSpecialization && filterPiece("templatespecialization"))
                ret["templatespecialization"] = true;
            if (symbol.flags & Symbol::TemplateReference && filterPiece("templatereference"))
                ret["templatereference"] = true;
            if (f & IncludeTargets) {
                const auto targets = project->findTargets(symbol);
                if (!targets.isEmpty() && filterPiece("targets")) {
                    Value t;
                    for (const auto &target : targets) {
                        t.push_back(toValue(target, NullFlags));
                    }
                    ret["targets"] = t;
                }
            }
            if (f & IncludeReferences) {
                const auto references = project->findCallers(symbol);
                if (!references.isEmpty() && filterPiece("references")) {
                    Value r;
                    for (const auto &ref : references) {
                        r.push_back(toValue(ref, NullFlags));
                    }
                    ret["references"] = r;
                }
            }
            if (f & IncludeBaseClasses && filterPiece("baseclasses")) {
                List<Value> b;
                for (const auto &base : symbol.baseClasses) {
                    for (const Symbol &s : project->findByUsr(base, symbol.location.fileId(), Project::ArgDependsOn)) {
                        b.append(toValue(s, NullFlags));
                        break;
                    }
                }
                if (!baseClasses.isEmpty()) {
                    ret["baseClasses"] = b;
                }
            }

            if ((f & IncludeParents && filterPiece("parent"))
                || (f & (IncludeContainingFunction) && filterPiece("cf"))
                || (f & (IncludeContainingFunctionLocation) && (filterPiece("cfl") || filterPiece("cflcontext")))) {
                auto syms = project->openSymbols(symbol.location.fileId());
                uint32_t idx = -1;
                if (syms) {
                    idx = syms->lowerBound(symbol.location);
                    if (idx == std::numeric_limits<uint32_t>::max()) {
                        idx = syms->count() - 1;
                    }
                }
                const unsigned int line = symbol.location.line();
                const unsigned int column = symbol.location.column();
                while (idx-- > 0) {
                    const Symbol s = syms->valueAt(idx);
                    if (s.isDefinition()
                        && s.isContainer()
                        && comparePosition(line, column, s.startLine, s.startColumn) >= 0
                        && comparePosition(line, column, s.endLine, s.endColumn) <= 0) {
                        if (f & IncludeContainingFunctionLocation) {
                            formatLocation(s.location, "cfl", "cflcontext");
                        }
                        if (f & IncludeContainingFunction && filterPiece("cf"))
                            ret["cf"] = s.symbolName;
                        if (f & IncludeParents && filterPiece("parent"))
                            ret["parent"] = toValue(s, IncludeParents);
                        break;
                    }
                }
            }
        }
        return ret;
    };
    return toValue(*this, toStringFlags);
}
Esempio n. 7
0
Value Symbol::toValue(const std::shared_ptr<Project> &project,
                      Flags<ToStringFlag> toStringFlags,
                      Flags<Location::ToStringFlag> locationToStringFlags) const
{
    std::function<Value(const Symbol &, Flags<ToStringFlag>)> toValue = [&](const Symbol &symbol, Flags<ToStringFlag> f) {
        Value ret;
        if (!symbol.isNull()) {
            ret["location"] = symbol.location.toString(locationToStringFlags);
            if (symbol.argumentUsage.index != String::npos) {
                ret["invocation"] = symbol.argumentUsage.invocation.toString(locationToStringFlags);
                ret["invokedFunction"] = symbol.argumentUsage.invokedFunction.toString(locationToStringFlags);
                ret["functionArgumentLocation"] = symbol.argumentUsage.argument.location.toString(locationToStringFlags);
                ret["functionArgumentCursor"] = symbol.argumentUsage.argument.cursor.toString(locationToStringFlags);
                ret["functionArgumentLength"] = symbol.argumentUsage.argument.length;
                ret["argumentIndex"] = symbol.argumentUsage.index;
            }
            if (!symbol.symbolName.isEmpty())
                ret["symbolName"] = symbol.symbolName;
            if (!symbol.usr.isEmpty())
                ret["usr"] = symbol.usr;
            if (!symbol.typeName.isEmpty()) {
                ret["type"] = symbol.typeName;
            } else if (symbol.type != CXType_Invalid) {
                String str;
                Log(&str) << symbol.type;
                ret["type"] = str;
            }

            if (!symbol.baseClasses.isEmpty())
                ret["baseClasses"] = symbol.baseClasses;
            if (!symbol.arguments.isEmpty()) {
                Value args;
                for (const auto &arg : symbol.arguments) {
                    Value a;
                    a["location"] = arg.location.toString(locationToStringFlags);
                    a["cursor"] = arg.cursor.toString(locationToStringFlags);
                    a["length"] = arg.length;
                    args.push_back(a);
                }
                ret["arguments"] = args;
            }
            ret["symbolLength"] = symbol.symbolLength;
            {
                String str;
                Log(&str) << symbol.kind;
                ret["kind"] = str;
            }
            {
                String str;
                Log(&str) << symbol.linkage;
                ret["linkage"] = str;
            }

            if (!symbol.briefComment.isEmpty())
                ret["briefComment"] = symbol.briefComment;
            if (!symbol.xmlComment.isEmpty())
                ret["xmlComment"] = symbol.xmlComment;
            ret["startLine"] = symbol.startLine;
            ret["startColumn"] = symbol.startColumn;
            ret["endLine"] = symbol.endLine;
            ret["endColumn"] = symbol.endColumn;
            if (symbol.size > 0)
                ret["sizeof"] = symbol.size;
            if (symbol.fieldOffset > 0)
                ret["fieldOffset"] = symbol.fieldOffset;
            if (symbol.alignment > 0)
                ret["alignment"] = symbol.alignment;
            if (symbol.kind == CXCursor_EnumConstantDecl)
                ret["enumValue"] = symbol.enumValue;
            if (symbol.isDefinition()) {
                ret["definition"] = true;
                if (RTags::isFunction(symbol.kind))
                    ret["stackCost"] = symbol.stackCost;
            } else if (symbol.isReference()) {
                ret["reference"] = true;
            }
            if (symbol.isContainer())
                ret["container"] = true;
            if ((symbol.flags & Symbol::PureVirtualMethod) == Symbol::PureVirtualMethod)
                ret["purevirtual"] = true;
            if (symbol.flags & Symbol::VirtualMethod)
                ret["virtual"] = true;
            if (symbol.flags & Symbol::ConstMethod)
                ret["constmethod"] = true;
            if (symbol.flags & Symbol::StaticMethod)
                ret["staticmethod"] = true;
            if (symbol.flags & Symbol::Variadic)
                ret["variadic"] = true;
            if (symbol.flags & Symbol::Auto)
                ret["auto"] = true;
            if (symbol.flags & Symbol::AutoRef)
                ret["autoref"] = true;
            if (symbol.flags & Symbol::MacroExpansion)
                ret["macroexpansion"] = true;
            if (symbol.flags & Symbol::TemplateSpecialization)
                ret["templatespecialization"] = true;
            if (f & IncludeTargets) {
                const auto targets = project->findTargets(symbol);
                if (!targets.isEmpty()) {
                    Value t;
                    for (const auto &target : targets) {
                        t.push_back(toValue(target, NullFlags));
                    }
                    ret["targets"] = t;
                }
            }
            if (f & IncludeReferences) {
                const auto references = project->findCallers(symbol);
                if (!references.isEmpty()) {
                    Value r;
                    for (const auto &ref : references) {
                        r.push_back(toValue(ref, NullFlags));
                    }
                    ret["references"] = r;
                }
            }
            if (f & IncludeBaseClasses) {
                List<Value> b;
                for (const auto &base : symbol.baseClasses) {
                    for (const Symbol &s : project->findByUsr(base, symbol.location.fileId(), Project::ArgDependsOn, symbol.location)) {
                        b.append(toValue(s, NullFlags));
                        break;
                    }
                }
                if (!baseClasses.isEmpty()) {
                    ret["baseClasses"] = b;
                }
            }

            if (f & IncludeParents) {
                auto syms = project->openSymbols(symbol.location.fileId());
                uint32_t idx = -1;
                if (syms) {
                    idx = syms->lowerBound(symbol.location);
                    if (idx == std::numeric_limits<uint32_t>::max()) {
                        idx = syms->count() - 1;
                    }
                }
                const unsigned int line = symbol.location.line();
                const unsigned int column = symbol.location.column();
                while (idx-- > 0) {
                    const Symbol s = syms->valueAt(idx);
                    if (s.isDefinition()
                        && s.isContainer()
                        && comparePosition(line, column, s.startLine, s.startColumn) >= 0
                        && comparePosition(line, column, s.endLine, s.endColumn) <= 0) {
                        ret["parent"] = toValue(s, IncludeParents);
                        break;
                    }
                }
            }
        }
        return ret;
    };
    return toValue(*this, toStringFlags);
}