summaryrefslogtreecommitdiff
path: root/graphics/asymptote/symbolmaps.cc
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-12-28 03:01:00 +0000
committerNorbert Preining <norbert@preining.info>2021-12-28 03:01:00 +0000
commitecdf859b6ce481abfd530425dcf6f0f764bd0001 (patch)
tree13bc161dc046876ac6c92fce5f9f5034ba9aa573 /graphics/asymptote/symbolmaps.cc
parent790995b7e79697514364450bf9c04f1b8d500838 (diff)
CTAN sync 202112280300
Diffstat (limited to 'graphics/asymptote/symbolmaps.cc')
-rw-r--r--graphics/asymptote/symbolmaps.cc828
1 files changed, 828 insertions, 0 deletions
diff --git a/graphics/asymptote/symbolmaps.cc b/graphics/asymptote/symbolmaps.cc
new file mode 100644
index 0000000000..27c073e70b
--- /dev/null
+++ b/graphics/asymptote/symbolmaps.cc
@@ -0,0 +1,828 @@
+#include "common.h"
+
+#ifdef HAVE_LSP
+
+#include "symbolmaps.h"
+#include "locate.h"
+#include <unordered_map>
+
+namespace AsymptoteLsp
+{
+ [[nodiscard]]
+ bool isVirtualFile(std::string const& filename)
+ {
+ bool isSettings=filename=="settings";
+#ifdef HAVE_LIBGSL
+ bool isGSL=filename=="gsl" and settings::getSetting<bool>("gsl");
+#else
+ bool isGSL=false;
+#endif
+ return isSettings || isGSL;
+ }
+
+ std::string getPlainFile()
+ {
+ return std::string((std::string) settings::locateFile("plain", true).c_str());
+ }
+
+ positions::positions(filePos const& positionInFile)
+ {
+ add(positionInFile);
+ }
+
+ void positions::add(const filePos &positionInFile)
+ {
+ auto fileLoc=pos.find(positionInFile.first);
+ if (fileLoc == pos.end())
+ {
+ pos.emplace(positionInFile.first, std::vector<posInFile>{positionInFile.second});
+ } else
+ {
+ fileLoc->second.push_back(positionInFile.second);
+ }
+ }
+
+ ostream& operator <<(std::ostream& os, const SymbolMaps& sym)
+ {
+ os << "var decs:" << endl;
+ for (auto const& s : sym.varDec)
+ {
+ auto const& key=std::get<0>(s);
+ auto const& value=std::get<1>(s);
+ os << key << " " << value.pos.first << ":" << value.pos.second << endl;
+ }
+ return os;
+ }
+
+ optional<fullSymPosRangeInFile> SymbolMaps::searchSymbol(posInFile const& inputPos)
+ {
+ // FIXME: can be optimized by binary search.
+ for (auto const& s : usageByLines)
+ {
+ auto const& pos=std::get<0>(s);
+ auto const& syLit=std::get<1>(s);
+ size_t endCharacter = pos.second + syLit.name.length() - 1;
+ bool posMatches =
+ pos.first == inputPos.first and
+ pos.second <= inputPos.second and
+ inputPos.second <= endCharacter;
+ bool isOperator = syLit.name.find("operator ") == 0;
+ if (posMatches and !isOperator)
+ {
+ posInFile endPos(pos.first, endCharacter + 1);
+ return boost::make_optional(std::make_tuple(syLit, pos, endPos));
+ }
+ }
+ return nullopt;
+ }
+
+ FunctionInfo& SymbolMaps::addFunDef(
+ std::string const& funcName, posInFile const& position, std::string const& returnType)
+ {
+ auto fit=std::get<0>(funDec.emplace(std::piecewise_construct,
+ std::forward_as_tuple(funcName), std::forward_as_tuple()));
+
+ fit->second.emplace_back(funcName, position, returnType);
+ return fit->second.back();
+ }
+
+ std::pair<optional<fullSymPosRangeInFile>, SymbolContext*> SymbolContext::searchSymbol(posInFile const& inputPos)
+ {
+ auto currCtxSym = symMap.searchSymbol(inputPos);
+ if (currCtxSym.has_value())
+ {
+ return make_pair(currCtxSym, this);
+ }
+ // else, not found in currCtx;
+ for (auto& subContext : subContexts)
+ {
+ if (!posLt(inputPos, subContext->contextLoc))
+ {
+ auto v=subContext->searchSymbol(inputPos);
+ auto subCtxSym=std::get<0>(v);;
+ auto ctx=std::get<1>(v);
+ if (subCtxSym.has_value())
+ {
+ return make_pair(subCtxSym, ctx);
+ }
+ }
+ }
+ return make_pair(nullopt, nullptr);
+ }
+
+ SymbolInfo const* SymbolContext::searchVarRaw(std::string const& symbol) const
+ {
+ // local variable declarations
+ auto pt = symMap.varDec.find(symbol);
+ if (pt != symMap.varDec.end())
+ {
+ return &pt->second;
+ }
+
+ // otherwise, search parent.
+ return parent != nullptr ? parent->searchVarRaw(symbol) : nullptr;
+ }
+
+ optional<posRangeInFile> SymbolContext::searchVarDecl(
+ std::string const& symbol, optional<posInFile> const& position)
+ {
+ auto pt = symMap.varDec.find(symbol);
+ if (pt != symMap.varDec.end())
+ {
+ auto line = std::get<0>(pt->second.pos);
+ auto ch = std::get<1>(pt->second.pos);
+ if ((not position.has_value()) or (!posLt(position.value(), pt->second.pos)))
+ {
+ return std::make_tuple(getFileName().value_or(""),
+ pt->second.pos, std::make_pair(line, ch + symbol.length()));
+ }
+ }
+
+ auto ptFn = symMap.funDec.find(symbol);
+ if (ptFn != symMap.funDec.end() and !ptFn->second.empty())
+ {
+ // FIXME: Right now, we have no way of knowing the exact position of the
+ // start of where the function name is. As an example, we do not know
+ // where the exact position of
+ // real testFunction(...) { ...
+ // ^
+ auto ptValue = ptFn->second[0];
+ if ((not position.has_value()) or (!posLt(position.value(), ptValue.pos)))
+ {
+ return std::make_tuple(getFileName().value_or(""), ptValue.pos, ptValue.pos);
+ }
+ }
+
+ // otherwise, search parent.
+ return parent != nullptr ? parent->searchVarDecl(symbol, position) : nullopt;
+ }
+
+ void SymbolContext::addPlainFile()
+ {
+ std::string plainFile = getPlainFile();
+ addEmptyExtRef(plainFile);
+ }
+
+ SymbolContext::SymbolContext(posInFile loc):
+ fileLoc(nullopt), contextLoc(std::move(loc)), parent(nullptr)
+ {
+ addPlainFile();
+ }
+
+ SymbolContext::SymbolContext(posInFile loc, std::string filename):
+ fileLoc(std::move(filename)), contextLoc(std::move(loc)), parent(nullptr)
+ {
+ addPlainFile();
+ }
+
+ optional<posRangeInFile>
+ SymbolContext::searchVarDeclFull(std::string const& symbol, optional<posInFile> const& position)
+ {
+ std::unordered_set<SymbolContext*> searched;
+ std::unordered_set<std::string> symbolSearch { symbol };
+
+ auto returnVal = _searchVarFull<posRangeInFile>(
+ searched, symbolSearch,
+ [&position](SymbolContext* ctx, std::string const& sym)
+ {
+ return ctx->searchVarDecl(sym, position);
+ },
+ [](SymbolContext* ctx, std::string const& sym)
+ {
+ return ctx->searchVarDecl(sym);
+ },
+ fnFromDeclCreateTrav);
+ if (returnVal.has_value())
+ {
+ return returnVal;
+ }
+
+ return _searchVarFull<posRangeInFile>(
+ symbol,
+ [](SymbolContext* ctx, std::string const& sym) -> optional<posRangeInFile>
+ {
+ for (auto const& unravelVal : ctx->extRefs.unraveledVals)
+ {
+ if (auto* pctx=ctx->searchStructCtxFull(unravelVal))
+ {
+ auto retVal = pctx->searchVarDecl(sym);
+ if (retVal.has_value())
+ {
+ return retVal;
+ }
+ }
+ }
+ return nullopt;
+ });
+ }
+
+ std::list<ExternalRefs::extRefMap::iterator> SymbolContext::getEmptyRefs()
+ {
+ std::list<ExternalRefs::extRefMap::iterator> finalList;
+
+ for (auto it = extRefs.extFileRefs.begin(); it != extRefs.extFileRefs.end(); it++)
+ {
+ if (it->second == nullptr)
+ {
+ // cerr << it->first << endl;
+ finalList.emplace_back(it);
+ }
+ }
+
+ for (auto& ctx : subContexts)
+ {
+ finalList.splice(finalList.end(), ctx->getEmptyRefs());
+ }
+
+ return finalList;
+ }
+
+ optional<std::string> SymbolContext::getFileName() const
+ {
+ if (fileLoc.has_value())
+ {
+ return fileLoc;
+ }
+ else
+ {
+ return parent == nullptr ? fileLoc : parent->getFileName();
+ }
+ }
+
+ optional<std::string> SymbolContext::searchVarSignatureFull(std::string const& symbol)
+ {
+ std::unordered_set<SymbolContext*> searched;
+ auto retVal = _searchVarFull<std::string>(
+ symbol,
+ [](SymbolContext const* ctx, std::string const& sym) -> optional<std::string>
+ {
+ if (auto const* info = ctx->searchVarRaw(sym))
+ {
+ return info->signature();
+ }
+ return nullopt;
+ },
+ fnFromDeclCreateTrav);
+
+ if (retVal.has_value())
+ {
+ return retVal;
+ }
+
+ // else,
+ // search every unravel values possible (not only here, but also in every includes + unravels as well).
+ // If an unravel value match a struct, then see if symbol matches the struct. If yes, return otherwise skip.
+
+ return _searchVarFull<std::string>(
+ symbol,
+ [](SymbolContext* ctx, std::string const& sym) -> optional<std::string>
+ {
+ if (SymbolInfo* info=ctx->searchVarUnravelStructRaw(sym))
+ {
+ return info->signature();
+ }
+ return nullopt;
+ });
+ }
+
+ SymbolInfo* SymbolContext::searchVarUnravelStructRaw(std::string const& symbol)
+ {
+ return searchVarUnravelStructRaw(symbol, nullopt);
+ }
+
+ SymbolInfo* SymbolContext::searchVarUnravelStructRaw(std::string const& symbol, optional<posInFile> const& position)
+ {
+ for (auto const& unravelVal : extRefs.unraveledVals)
+ {
+ if (auto* ctx=searchStructCtxFull(unravelVal))
+ {
+ // ctx points to a struct.
+ auto it=ctx->symMap.varDec.find(symbol);
+ if (it != ctx->symMap.varDec.end())
+ {
+ if (((not position.has_value()) or (!posLt(position.value(), it->second.pos))))
+ {
+ return &it->second;
+ }
+ }
+ }
+ }
+ return parent != nullptr ? parent->searchVarUnravelStructRaw(symbol) : nullptr;
+ }
+
+ std::list<std::string> SymbolContext::searchFuncUnravelStruct(std::string const& symbol)
+ {
+ std::list<std::string> finalList;
+
+ for (auto const& unravelVal : extRefs.unraveledVals)
+ {
+ if (auto* ctx=searchStructCtxFull(unravelVal))
+ {
+ // ctx points to a struct.
+ auto it=ctx->symMap.funDec.find(symbol);
+ if (it != ctx->symMap.funDec.end() and not it->second.empty())
+ {
+ std::transform(
+ it->second.begin(), it->second.end(), std::back_inserter(finalList),
+ [](FunctionInfo const& fnInfo)
+ {
+ return fnInfo.signature();
+ });
+ }
+ }
+ }
+ if (parent != nullptr)
+ {
+ finalList.splice(finalList.end(), parent->searchFuncUnravelStruct(symbol));
+ }
+ return finalList;
+ }
+
+
+ std::list<std::string> SymbolContext::searchFuncSignature(std::string const& symbol)
+ {
+ std::list<std::string> funcSigs;
+ auto pt = symMap.funDec.find(symbol);
+ if (pt != symMap.funDec.end())
+ {
+ std::transform(pt->second.begin(), pt->second.end(),
+ std::back_inserter(funcSigs),
+ [](FunctionInfo const& fnInfo) {
+ return fnInfo.signature();
+ });
+ }
+
+ if (parent != nullptr)
+ {
+ funcSigs.splice(funcSigs.end(), parent->searchFuncSignature(symbol));
+ }
+ return funcSigs;
+ }
+
+ std::list<std::string> SymbolContext::searchFuncSignatureFull(std::string const& symbol)
+ {
+ auto base_list = _searchAllVarFull<std::string>(
+ symbol, std::mem_fn(&SymbolContext::searchFuncSignature), fnFromDeclCreateTrav);
+
+ base_list.splice(base_list.end(), _searchAllVarFull<std::string>(
+ symbol, std::mem_fn(&SymbolContext::searchFuncUnravelStruct)));
+ return base_list;
+ }
+
+ optional<SymbolContext*> SymbolContext::searchStructContext(std::string const& tyVal) const
+ {
+ auto stCtx = symMap.typeDecs.find(tyVal);
+ if (stCtx != symMap.typeDecs.end())
+ {
+ if (auto* stDec = dynamic_cast<StructDecs*>(stCtx->second.get()))
+ {
+ return make_optional(stDec->ctx);
+ }
+ }
+
+ return parent != nullptr ? parent->searchStructContext(tyVal) : nullopt;
+ };
+
+ optional<std::string> SymbolContext::searchLitSignature(SymbolLit const& symbol)
+ {
+ if (symbol.scopes.empty())
+ {
+ return searchVarSignatureFull(symbol.name);
+ }
+ else
+ {
+ auto ctx=std::get<0>(searchLitContext(symbol));
+ auto isStruct=std::get<1>(searchLitContext(symbol));
+ if (ctx)
+ {
+ if (isStruct)
+ {
+ // ctx is a struct declaration. should not search beyond this struct.
+ auto varDec=ctx->symMap.varDec.find(symbol.name);
+ return varDec != ctx->symMap.varDec.end() ?
+ optional<std::string>(varDec->second.signature()) : nullopt;
+ }
+ else
+ {
+ return ctx->searchVarSignatureFull(symbol.name);
+ }
+ }
+ }
+
+ return nullopt;
+ }
+
+ std::list<std::string> SymbolContext::searchLitFuncSignature(SymbolLit const& symbol)
+ {
+ std::list<std::string> signatures;
+ if (symbol.scopes.empty())
+ {
+ signatures.splice(signatures.end(), searchFuncSignatureFull(symbol.name));
+ }
+ else
+ {
+ auto ctx=std::get<0>(searchLitContext(symbol));
+ auto isStruct=std::get<1>(searchLitContext(symbol));
+ if (ctx)
+ {
+ if (isStruct)
+ {
+ // ctx is a struct declaration. should not search beyond this struct.
+ auto fnDecs=ctx->symMap.funDec.find(symbol.name);
+ if (fnDecs != ctx->symMap.funDec.end())
+ {
+ std::transform(
+ fnDecs->second.begin(), fnDecs->second.end(),
+ std::back_inserter(signatures),
+ [&scopes=symbol.scopes](FunctionInfo const& fnInf)
+ {
+ return fnInf.signature(scopes);
+ });
+ }
+ }
+ else
+ {
+ signatures.splice(signatures.end(), searchFuncSignatureFull(symbol.name));
+ }
+ }
+ }
+
+ return signatures;
+ }
+
+ optional<posRangeInFile> SymbolContext::searchLitPosition(
+ SymbolLit const& symbol,
+ optional<posInFile> const& position)
+ {
+ if (symbol.scopes.empty())
+ {
+ return searchVarDeclFull(symbol.name, position);
+ }
+ else
+ {
+ auto ctx=std::get<0>(searchLitContext(symbol));
+ auto isStruct=std::get<1>(searchLitContext(symbol));
+ if (ctx) // ctx is a struct declaration. should not search beyond this struct.
+ {
+ if (isStruct)
+ {
+ auto varDec=ctx->symMap.varDec.find(symbol.name);
+ if (varDec != ctx->symMap.varDec.end())
+ {
+ auto line=std::get<0>(varDec->second.pos);
+ auto ch=std::get<1>(varDec->second.pos);
+ return std::make_tuple(ctx->getFileName().value_or(""),
+ varDec->second.pos, std::make_pair(line, ch + symbol.name.length()));
+ }
+ }
+ else
+ {
+ return searchVarDeclFull(symbol.name, position);
+ }
+ }
+ return nullopt;
+ }
+ }
+
+ std::list<posRangeInFile>
+ SymbolContext::searchLitFuncPositions(SymbolLit const& symbol, optional<posInFile> const& position)
+ {
+ if (symbol.scopes.empty())
+ {
+ return searchFuncDeclsFull(symbol.name, position);
+ }
+ else
+ {
+ std::list<posRangeInFile> fnDecls;
+ auto v=searchLitContext(symbol);
+ auto ctx=std::get<0>(v);
+ auto isStruct=std::get<1>(v);
+ if (ctx) // ctx is a struct declaration. should not search beyond this struct.
+ {
+ if (isStruct)
+ {
+ auto fnDec=ctx->symMap.funDec.find(symbol.name);
+ if (fnDec != ctx->symMap.funDec.end())
+ {
+ for (auto const& ptValue : fnDec->second)
+ {
+ fnDecls.emplace_back(getFileName().value_or(""), ptValue.pos, ptValue.pos);
+ }
+ }
+ }
+ else
+ {
+ return searchFuncDeclsFull(symbol.name, position);
+ }
+ }
+ return fnDecls;
+ }
+ }
+
+ SymbolContext* SymbolContext::searchStructCtxFull(std::string const& symbol)
+ {
+ std::unordered_set<SymbolContext*> searched;
+ optional<std::string> tyInfo=_searchVarFull<std::string, std::string>(
+ symbol,
+ [](SymbolContext const* ctx, std::string const& sym) -> optional<std::string>
+ {
+ if (auto const* info = ctx->searchVarRaw(sym))
+ {
+ return info->type;
+ }
+ return nullopt;
+ },
+ fnFromDeclCreateTrav);
+
+
+ if (not tyInfo.has_value())
+ {
+ return nullptr;
+ }
+
+ return _searchVarFull<SymbolContext*>(
+ tyInfo.value(), std::mem_fn(&SymbolContext::searchStructContext)).value_or(nullptr);
+ }
+
+ optional<SymbolContext*> SymbolContext::searchAccessDecls(std::string const& accessVal)
+ {
+ // fileIdPair includes accessVals
+
+ auto src=extRefs.fileIdPair.find(accessVal);
+ if (src != extRefs.fileIdPair.end())
+ {
+ std::string& fileSrc=src->second;
+ auto ctxMap=extRefs.extFileRefs.find(fileSrc);
+ if (ctxMap != extRefs.extFileRefs.end() && ctxMap->second != nullptr)
+ {
+ return ctxMap->second;
+ }
+ }
+
+ return parent != nullptr ? parent->searchAccessDecls(accessVal) : nullopt;
+ }
+
+ /**
+ * Fully search context for source structs or source file in access
+ * @param symbol Symbol to search
+ * @return pair of <code>[context, isStruct]</code>, where <code>isStruct</code> is true
+ * if the <code>context</code> is a struct, and false if the context is a file from access declaration.
+ * If context is nullptr, <code>isStruct</code>'s return does not have defined behavior.
+ */
+ std::pair<SymbolContext*, bool> SymbolContext::searchLitContext(SymbolLit const& symbol)
+ {
+ if (symbol.scopes.empty())
+ {
+ // if the symbol is empty, then we can access every variable, not just those in the struct context
+ // and hence should be treated as "not a struct", even if the variable is accessed in the struct.
+ // for example,
+ // int z; struct St { int x; int y=x+z; }
+ // here, x and z can be accessed in the struct context.
+ return std::make_pair(this, false);
+ }
+ else
+ {
+ std::vector<std::string> scopes(symbol.scopes);
+ bool isStruct=false;
+
+ // search in struct
+ auto* ctx=searchStructCtxFull(scopes.back());
+ if (ctx)
+ {
+ isStruct = true;
+ scopes.pop_back();
+ }
+ else
+ {
+ // search in access declarations
+ ctx =_searchVarFull<SymbolContext*>(
+ scopes.back(), std::mem_fn(&SymbolContext::searchAccessDecls)).value_or(nullptr);
+
+ if (ctx)
+ {
+ scopes.pop_back();
+ }
+ }
+
+ for (auto it = scopes.rbegin(); it != scopes.rend() and ctx != nullptr; it++)
+ {
+ // FIXME: Impelemnt scope searching
+ // example:
+ // varx.vary.varz => go into varx's type context (struct or external file), repeat.
+ // struct and extfile handled very differently
+
+ // get next variable declaration loc.
+ // assumes struct, hence we do not search entire workspace
+ SymbolContext* newCtx=nullptr;
+
+ auto locVarDec = ctx->symMap.varDec.find(*it);
+ if (locVarDec != ctx->symMap.varDec.end() and locVarDec->second.type.has_value())
+ {
+ newCtx = ctx->_searchVarFull<SymbolContext*>(
+ locVarDec->second.type.value(), std::mem_fn(&SymbolContext::searchStructContext)
+ ).value_or(nullptr);
+ }
+
+ // here, we searched for a struct context and did not find anything.
+ // If we are in a struct context, we hit a dead end.
+ // otherwise, we search for access declaration contexts.
+ if (newCtx == nullptr)
+ {
+ if (isStruct)
+ {
+ return make_pair(nullptr, false);
+ }
+ else
+ {
+ ctx =_searchVarFull<SymbolContext*>(
+ *it, std::mem_fn(&SymbolContext::searchAccessDecls)).value_or(nullptr);
+ }
+ }
+ else
+ {
+ isStruct = true;
+ }
+
+ ctx = newCtx;
+ }
+ return make_pair(ctx, isStruct);
+ }
+ }
+
+ std::unordered_set<std::string> SymbolContext::createTraverseSet()
+ {
+ std::unordered_set<std::string> traverseSet(extRefs.includeVals);
+ traverseSet.emplace(getPlainFile());
+ for (auto const& unravelVal : extRefs.unraveledVals)
+ {
+ auto it = extRefs.fileIdPair.find(unravelVal);
+ if (it != extRefs.fileIdPair.end())
+ {
+ traverseSet.emplace(it->second);
+ }
+ }
+ return traverseSet;
+ }
+
+ SymbolContext* SymbolContext::getExternalRef(std::string const& symbol)
+ {
+ auto symRef = extRefs.extFileRefs.find(symbol);
+ if (symRef != extRefs.extFileRefs.end())
+ {
+ return symRef->second;
+ }
+
+ return parent != nullptr ? parent->getExternalRef(symbol) : nullptr;
+ }
+
+ std::list<posRangeInFile> SymbolContext::searchFuncDecls(std::string const& symbol)
+ {
+ return searchFuncDecls(symbol, nullopt);
+ }
+
+ std::list<posRangeInFile>
+ SymbolContext::searchFuncDecls(std::string const& symbol, optional<posInFile> const& position)
+ {
+ std::list<posRangeInFile> funcDecls;
+ auto pt = symMap.funDec.find(symbol);
+ if (pt != symMap.funDec.end())
+ {
+ for (auto const& fnInfo : pt->second)
+ {
+ if ((not position.has_value()) or (!posLt(position.value(), fnInfo.pos)))
+ {
+ funcDecls.emplace_back(getFileName().value_or(""), fnInfo.pos, fnInfo.pos);
+ }
+ }
+ }
+
+ if (parent != nullptr)
+ {
+ funcDecls.splice(funcDecls.end(), parent->searchFuncDecls(symbol, position));
+ }
+ return funcDecls;
+ }
+
+ std::list<posRangeInFile>
+ SymbolContext::searchFuncDeclsFull(std::string const& symbol, optional<posInFile> const& position)
+ {
+ std::unordered_set<SymbolContext*> searched;
+ auto retVal = _searchAllVarFull<posRangeInFile>(
+ searched,
+ std::unordered_set<std::string> { symbol },
+ [&position](SymbolContext* ctx, std::string const& symbol)
+ {
+ return ctx->searchFuncDecls(symbol, position);
+ },
+ [](SymbolContext* ctx, std::string const& symbol)
+ {
+ return ctx->searchFuncDecls(symbol);
+ },
+ fnFromDeclCreateTrav);
+
+ auto retValStruct =_searchAllVarFull<posRangeInFile>(
+ symbol,
+ [](SymbolContext* ctx, std::string const& sym) -> std::list<posRangeInFile>
+ {
+ std::list<posRangeInFile> finalList;
+ for (auto const& unravelVal : ctx->extRefs.unraveledVals)
+ {
+ if (auto* pctx=ctx->searchStructCtxFull(unravelVal))
+ {
+ finalList.splice(finalList.end(), pctx->searchFuncDecls(sym));
+ }
+ }
+ return finalList;
+ });
+ retVal.splice(retVal.end(), std::move(retValStruct));
+ return retVal;
+ }
+
+ optional<posRangeInFile> AddDeclContexts::searchVarDecl(
+ std::string const& symbol, optional<posInFile> const& position)
+ {
+ auto pt = additionalDecs.find(symbol);
+ if (pt != additionalDecs.end())
+ {
+ auto line=std::get<0>(pt->second.pos);
+ auto ch=std::get<1>(pt->second.pos);
+ if ((not position.has_value()) or (!posLt(position.value(), pt->second.pos)))
+ {
+ return std::make_tuple(getFileName().value_or(""),
+ pt->second.pos,
+ std::make_pair(line, ch + symbol.length()));
+ }
+ }
+
+ return SymbolContext::searchVarDecl(symbol, position);
+ }
+
+ SymbolInfo const* AddDeclContexts::searchVarRaw(std::string const& symbol) const
+ {
+ auto pt = additionalDecs.find(symbol);
+ return pt != additionalDecs.end() ? &pt->second : SymbolContext::searchVarRaw(symbol);
+ }
+
+ bool SymbolInfo::operator==(SymbolInfo const& sym) const
+ {
+ return name==sym.name and type==sym.type and pos == sym.pos;
+ }
+
+ std::string SymbolInfo::signature() const
+ {
+ return type.value_or("<decl-unknown>") + " " + name + ";";
+ }
+
+ std::string FunctionInfo::signature() const
+ {
+ return signature(std::vector<std::string>());
+ }
+
+ std::string FunctionInfo::signature(std::vector<std::string> const& scopes) const
+ {
+ std::stringstream ss;
+ ss << returnType << " ";
+ for (auto it=scopes.crbegin(); it!=scopes.crend(); it++)
+ {
+ ss << *it << ".";
+ }
+ ss << name << "(";
+ for (auto it = arguments.begin(); it != arguments.end(); it++)
+ {
+ auto const& argtype=std::get<0>(*it);
+ auto const& argname=std::get<1>(*it);
+ ss << argtype;
+ if (argname.has_value())
+ {
+ ss << " " << argname.value();
+ }
+
+ if (std::next(it) != arguments.end())
+ {
+ ss << ",";
+ }
+
+ if (std::next(it) != arguments.end() or restArgs.has_value())
+ {
+ ss << " ";
+ }
+ }
+
+ if (restArgs.has_value())
+ {
+ auto const& v=restArgs.value();
+ auto const& argtype=std::get<0>(v);
+ auto const& argname=std::get<1>(v);
+ ss << "... " << argtype;
+
+ if (argname.has_value())
+ {
+ ss << " " << argname.value();
+ }
+ }
+ ss << ");";
+ return ss.str();
+ }
+}
+
+#endif