mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +00:00 
			
		
		
		
	Merge query.hh and query_util.hh
This commit is contained in:
		
							parent
							
								
									5a723b489a
								
							
						
					
					
						commit
						5a5165faa8
					
				@ -196,7 +196,6 @@ target_sources(ccls PRIVATE
 | 
				
			|||||||
  src/platform_win.cc
 | 
					  src/platform_win.cc
 | 
				
			||||||
  src/position.cc
 | 
					  src/position.cc
 | 
				
			||||||
  src/project.cc
 | 
					  src/project.cc
 | 
				
			||||||
  src/query_utils.cc
 | 
					 | 
				
			||||||
  src/query.cc
 | 
					  src/query.cc
 | 
				
			||||||
  src/serializer.cc
 | 
					  src/serializer.cc
 | 
				
			||||||
  src/test.cc
 | 
					  src/test.cc
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ limitations under the License.
 | 
				
			|||||||
#include "log.hh"
 | 
					#include "log.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "project.hh"
 | 
					#include "project.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
#include "serializers/json.hh"
 | 
					#include "serializers/json.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ limitations under the License.
 | 
				
			|||||||
#include "hierarchy.hh"
 | 
					#include "hierarchy.hh"
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ limitations under the License.
 | 
				
			|||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "project.hh"
 | 
					#include "project.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ccls {
 | 
					namespace ccls {
 | 
				
			||||||
MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, skipped_ranges,
 | 
					MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, skipped_ranges,
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ limitations under the License.
 | 
				
			|||||||
#include "hierarchy.hh"
 | 
					#include "hierarchy.hh"
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ limitations under the License.
 | 
				
			|||||||
#include "hierarchy.hh"
 | 
					#include "hierarchy.hh"
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <clang/AST/Type.h>
 | 
					#include <clang/AST/Type.h>
 | 
				
			||||||
#include <llvm/ADT/DenseSet.h>
 | 
					#include <llvm/ADT/DenseSet.h>
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ limitations under the License.
 | 
				
			|||||||
==============================================================================*/
 | 
					==============================================================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ccls {
 | 
					namespace ccls {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ limitations under the License.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ccls {
 | 
					namespace ccls {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ limitations under the License.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
#include "serializers/json.hh"
 | 
					#include "serializers/json.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <llvm/Support/FormatVariadic.h>
 | 
					#include <llvm/Support/FormatVariadic.h>
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ limitations under the License.
 | 
				
			|||||||
==============================================================================*/
 | 
					==============================================================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include <limits.h>
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ limitations under the License.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ limitations under the License.
 | 
				
			|||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "project.hh"
 | 
					#include "project.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
#include "working_files.hh"
 | 
					#include "working_files.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ccls {
 | 
					namespace ccls {
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ limitations under the License.
 | 
				
			|||||||
==============================================================================*/
 | 
					==============================================================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ccls {
 | 
					namespace ccls {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ limitations under the License.
 | 
				
			|||||||
==============================================================================*/
 | 
					==============================================================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <unordered_set>
 | 
					#include <unordered_set>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ limitations under the License.
 | 
				
			|||||||
==============================================================================*/
 | 
					==============================================================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ccls {
 | 
					namespace ccls {
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ limitations under the License.
 | 
				
			|||||||
#include "message_handler.hh"
 | 
					#include "message_handler.hh"
 | 
				
			||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "project.hh"
 | 
					#include "project.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <llvm/ADT/STLExtras.h>
 | 
					#include <llvm/ADT/STLExtras.h>
 | 
				
			||||||
#include <llvm/ADT/StringRef.h>
 | 
					#include <llvm/ADT/StringRef.h>
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@ limitations under the License.
 | 
				
			|||||||
#include "pipeline.hh"
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "platform.hh"
 | 
					#include "platform.hh"
 | 
				
			||||||
#include "project.hh"
 | 
					#include "project.hh"
 | 
				
			||||||
#include "query_utils.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
#include "serializers/json.hh"
 | 
					#include "serializers/json.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <rapidjson/document.h>
 | 
					#include <rapidjson/document.h>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										322
									
								
								src/query.cc
									
									
									
									
									
								
							
							
						
						
									
										322
									
								
								src/query.cc
									
									
									
									
									
								
							@ -16,11 +16,13 @@ limitations under the License.
 | 
				
			|||||||
#include "query.hh"
 | 
					#include "query.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "indexer.hh"
 | 
					#include "indexer.hh"
 | 
				
			||||||
 | 
					#include "pipeline.hh"
 | 
				
			||||||
#include "serializer.hh"
 | 
					#include "serializer.hh"
 | 
				
			||||||
#include "serializers/json.hh"
 | 
					#include "serializers/json.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cassert>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <cstdint>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
#include <functional>
 | 
					#include <functional>
 | 
				
			||||||
#include <optional>
 | 
					#include <optional>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
@ -52,7 +54,7 @@ void RemoveRange(std::vector<T> &from, const std::vector<T> &to_remove) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile &indexed) {
 | 
					QueryFile::DefUpdate BuildFileDefUpdate(IndexFile &&indexed) {
 | 
				
			||||||
  QueryFile::Def def;
 | 
					  QueryFile::Def def;
 | 
				
			||||||
  def.path = std::move(indexed.path);
 | 
					  def.path = std::move(indexed.path);
 | 
				
			||||||
  def.args = std::move(indexed.args);
 | 
					  def.args = std::move(indexed.args);
 | 
				
			||||||
@ -87,7 +89,6 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
 | 
				
			|||||||
  else
 | 
					  else
 | 
				
			||||||
    previous = ∅
 | 
					    previous = ∅
 | 
				
			||||||
  r.lid2path = std::move(current->lid2path);
 | 
					  r.lid2path = std::move(current->lid2path);
 | 
				
			||||||
  r.files_def_update = BuildFileDefUpdate(std::move(*current));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  r.funcs_hint = current->usr2func.size() - previous->usr2func.size();
 | 
					  r.funcs_hint = current->usr2func.size() - previous->usr2func.size();
 | 
				
			||||||
  for (auto &it : previous->usr2func) {
 | 
					  for (auto &it : previous->usr2func) {
 | 
				
			||||||
@ -143,6 +144,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
 | 
				
			|||||||
    r.vars_uses[var.usr].second = std::move(var.uses);
 | 
					    r.vars_uses[var.usr].second = std::move(var.uses);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  r.files_def_update = BuildFileDefUpdate(std::move(*current));
 | 
				
			||||||
  return r;
 | 
					  return r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -486,4 +488,316 @@ std::vector<uint8_t> DB::GetFileSet(const std::vector<std::string> &folders) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  return file_set;
 | 
					  return file_set;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace {
 | 
				
			||||||
 | 
					// Computes roughly how long |range| is.
 | 
				
			||||||
 | 
					int ComputeRangeSize(const Range &range) {
 | 
				
			||||||
 | 
					  if (range.start.line != range.end.line)
 | 
				
			||||||
 | 
					    return INT_MAX;
 | 
				
			||||||
 | 
					  return range.end.column - range.start.column;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Q>
 | 
				
			||||||
 | 
					std::vector<Use>
 | 
				
			||||||
 | 
					GetDeclarations(llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
 | 
				
			||||||
 | 
					                std::vector<Q> &entities, const std::vector<Usr> &usrs) {
 | 
				
			||||||
 | 
					  std::vector<Use> ret;
 | 
				
			||||||
 | 
					  ret.reserve(usrs.size());
 | 
				
			||||||
 | 
					  for (Usr usr : usrs) {
 | 
				
			||||||
 | 
					    Q &entity = entities[entity_usr[{usr}]];
 | 
				
			||||||
 | 
					    bool has_def = false;
 | 
				
			||||||
 | 
					    for (auto &def : entity.def)
 | 
				
			||||||
 | 
					      if (def.spell) {
 | 
				
			||||||
 | 
					        ret.push_back(*def.spell);
 | 
				
			||||||
 | 
					        has_def = true;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    if (!has_def && entity.declarations.size())
 | 
				
			||||||
 | 
					      ret.push_back(entity.declarations[0]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym) {
 | 
				
			||||||
 | 
					  Maybe<DeclRef> ret;
 | 
				
			||||||
 | 
					  EachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.spell); });
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
 | 
				
			||||||
 | 
					  return GetDeclarations(db->func_usr, db->funcs, usrs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
 | 
				
			||||||
 | 
					  return GetDeclarations(db->type_usr, db->types, usrs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
 | 
				
			||||||
 | 
					                                    unsigned kind) {
 | 
				
			||||||
 | 
					  std::vector<Use> ret;
 | 
				
			||||||
 | 
					  ret.reserve(usrs.size());
 | 
				
			||||||
 | 
					  for (Usr usr : usrs) {
 | 
				
			||||||
 | 
					    QueryVar &var = db->Var(usr);
 | 
				
			||||||
 | 
					    bool has_def = false;
 | 
				
			||||||
 | 
					    for (auto &def : var.def)
 | 
				
			||||||
 | 
					      if (def.spell) {
 | 
				
			||||||
 | 
					        has_def = true;
 | 
				
			||||||
 | 
					        // See messages/ccls_vars.cc
 | 
				
			||||||
 | 
					        if (def.kind == SymbolKind::Field) {
 | 
				
			||||||
 | 
					          if (!(kind & 1))
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        } else if (def.kind == SymbolKind::Variable) {
 | 
				
			||||||
 | 
					          if (!(kind & 2))
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        } else if (def.kind == SymbolKind::Parameter) {
 | 
				
			||||||
 | 
					          if (!(kind & 4))
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret.push_back(*def.spell);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    if (!has_def && var.declarations.size())
 | 
				
			||||||
 | 
					      ret.push_back(var.declarations[0]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym) {
 | 
				
			||||||
 | 
					  static std::vector<DeclRef> empty;
 | 
				
			||||||
 | 
					  switch (sym.kind) {
 | 
				
			||||||
 | 
					  case Kind::Func:
 | 
				
			||||||
 | 
					    return db->GetFunc(sym).declarations;
 | 
				
			||||||
 | 
					  case Kind::Type:
 | 
				
			||||||
 | 
					    return db->GetType(sym).declarations;
 | 
				
			||||||
 | 
					  case Kind::Var:
 | 
				
			||||||
 | 
					    return db->GetVar(sym).declarations;
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return empty;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {
 | 
				
			||||||
 | 
					  std::vector<Use> ret;
 | 
				
			||||||
 | 
					  std::vector<QueryFunc *> stack{&root};
 | 
				
			||||||
 | 
					  std::unordered_set<Usr> seen;
 | 
				
			||||||
 | 
					  seen.insert(root.usr);
 | 
				
			||||||
 | 
					  while (!stack.empty()) {
 | 
				
			||||||
 | 
					    QueryFunc &func = *stack.back();
 | 
				
			||||||
 | 
					    stack.pop_back();
 | 
				
			||||||
 | 
					    if (auto *def = func.AnyDef()) {
 | 
				
			||||||
 | 
					      EachDefinedFunc(db, def->bases, [&](QueryFunc &func1) {
 | 
				
			||||||
 | 
					        if (!seen.count(func1.usr)) {
 | 
				
			||||||
 | 
					          seen.insert(func1.usr);
 | 
				
			||||||
 | 
					          stack.push_back(&func1);
 | 
				
			||||||
 | 
					          ret.insert(ret.end(), func1.uses.begin(), func1.uses.end());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
 | 
				
			||||||
 | 
					  std::vector<Use> ret;
 | 
				
			||||||
 | 
					  std::vector<QueryFunc *> stack{&root};
 | 
				
			||||||
 | 
					  std::unordered_set<Usr> seen;
 | 
				
			||||||
 | 
					  seen.insert(root.usr);
 | 
				
			||||||
 | 
					  while (!stack.empty()) {
 | 
				
			||||||
 | 
					    QueryFunc &func = *stack.back();
 | 
				
			||||||
 | 
					    stack.pop_back();
 | 
				
			||||||
 | 
					    EachDefinedFunc(db, func.derived, [&](QueryFunc &func1) {
 | 
				
			||||||
 | 
					      if (!seen.count(func1.usr)) {
 | 
				
			||||||
 | 
					        seen.insert(func1.usr);
 | 
				
			||||||
 | 
					        stack.push_back(&func1);
 | 
				
			||||||
 | 
					        ret.insert(ret.end(), func1.uses.begin(), func1.uses.end());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::optional<lsRange> GetLsRange(WorkingFile *wfile,
 | 
				
			||||||
 | 
					                                  const Range &location) {
 | 
				
			||||||
 | 
					  if (!wfile || wfile->index_lines.empty())
 | 
				
			||||||
 | 
					    return lsRange{Position{location.start.line, location.start.column},
 | 
				
			||||||
 | 
					                   Position{location.end.line, location.end.column}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int start_column = location.start.column, end_column = location.end.column;
 | 
				
			||||||
 | 
					  std::optional<int> start = wfile->GetBufferPosFromIndexPos(
 | 
				
			||||||
 | 
					      location.start.line, &start_column, false);
 | 
				
			||||||
 | 
					  std::optional<int> end = wfile->GetBufferPosFromIndexPos(
 | 
				
			||||||
 | 
					      location.end.line, &end_column, true);
 | 
				
			||||||
 | 
					  if (!start || !end)
 | 
				
			||||||
 | 
					    return std::nullopt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If remapping end fails (end can never be < start), just guess that the
 | 
				
			||||||
 | 
					  // final location didn't move. This only screws up the highlighted code
 | 
				
			||||||
 | 
					  // region if we guess wrong, so not a big deal.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Remapping fails often in C++ since there are a lot of "};" at the end of
 | 
				
			||||||
 | 
					  // class/struct definitions.
 | 
				
			||||||
 | 
					  if (*end < *start)
 | 
				
			||||||
 | 
					    *end = *start + (location.end.line - location.start.line);
 | 
				
			||||||
 | 
					  if (*start == *end && start_column > end_column)
 | 
				
			||||||
 | 
					    end_column = start_column;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return lsRange{Position{*start, start_column}, Position{*end, end_column}};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path) {
 | 
				
			||||||
 | 
					  QueryFile &file = db->files[file_id];
 | 
				
			||||||
 | 
					  if (file.def) {
 | 
				
			||||||
 | 
					    *path = file.def->path;
 | 
				
			||||||
 | 
					    return DocumentUri::FromPath(*path);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    *path = "";
 | 
				
			||||||
 | 
					    return DocumentUri::FromPath("");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DocumentUri GetLsDocumentUri(DB *db, int file_id) {
 | 
				
			||||||
 | 
					  QueryFile &file = db->files[file_id];
 | 
				
			||||||
 | 
					  if (file.def) {
 | 
				
			||||||
 | 
					    return DocumentUri::FromPath(file.def->path);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return DocumentUri::FromPath("");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use) {
 | 
				
			||||||
 | 
					  std::string path;
 | 
				
			||||||
 | 
					  DocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
 | 
				
			||||||
 | 
					  std::optional<lsRange> range =
 | 
				
			||||||
 | 
					      GetLsRange(wfiles->GetFileByFilename(path), use.range);
 | 
				
			||||||
 | 
					  if (!range)
 | 
				
			||||||
 | 
					    return std::nullopt;
 | 
				
			||||||
 | 
					  return Location{uri, *range};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
 | 
					                                      SymbolRef sym, int file_id) {
 | 
				
			||||||
 | 
					  return GetLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
 | 
					                                     const std::vector<Use> &uses) {
 | 
				
			||||||
 | 
					  std::vector<Location> ret;
 | 
				
			||||||
 | 
					  for (Use use : uses)
 | 
				
			||||||
 | 
					    if (auto loc = GetLsLocation(db, wfiles, use))
 | 
				
			||||||
 | 
					      ret.push_back(*loc);
 | 
				
			||||||
 | 
					  std::sort(ret.begin(), ret.end());
 | 
				
			||||||
 | 
					  ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
 | 
				
			||||||
 | 
					  if (ret.size() > g_config->xref.maxNum)
 | 
				
			||||||
 | 
					    ret.resize(g_config->xref.maxNum);
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
 | 
				
			||||||
 | 
					  SymbolKind ret;
 | 
				
			||||||
 | 
					  if (sym.kind == Kind::File)
 | 
				
			||||||
 | 
					    ret = SymbolKind::File;
 | 
				
			||||||
 | 
					  else {
 | 
				
			||||||
 | 
					    ret = SymbolKind::Unknown;
 | 
				
			||||||
 | 
					    WithEntity(db, sym, [&](const auto &entity) {
 | 
				
			||||||
 | 
					      for (auto &def : entity.def) {
 | 
				
			||||||
 | 
					        ret = def.kind;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
				
			||||||
 | 
					                                               bool detailed) {
 | 
				
			||||||
 | 
					  switch (sym.kind) {
 | 
				
			||||||
 | 
					  case Kind::Invalid:
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case Kind::File: {
 | 
				
			||||||
 | 
					    QueryFile &file = db->GetFile(sym);
 | 
				
			||||||
 | 
					    if (!file.def)
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SymbolInformation info;
 | 
				
			||||||
 | 
					    info.name = file.def->path;
 | 
				
			||||||
 | 
					    info.kind = SymbolKind::File;
 | 
				
			||||||
 | 
					    return info;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  default: {
 | 
				
			||||||
 | 
					    SymbolInformation info;
 | 
				
			||||||
 | 
					    EachEntityDef(db, sym, [&](const auto &def) {
 | 
				
			||||||
 | 
					      if (detailed)
 | 
				
			||||||
 | 
					        info.name = def.detailed_name;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        info.name = def.Name(true);
 | 
				
			||||||
 | 
					      info.kind = def.kind;
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return info;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return std::nullopt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
 | 
				
			||||||
 | 
					                                             QueryFile *file, Position &ls_pos,
 | 
				
			||||||
 | 
					                                             bool smallest) {
 | 
				
			||||||
 | 
					  std::vector<SymbolRef> symbols;
 | 
				
			||||||
 | 
					  // If multiVersion > 0, index may not exist and thus index_lines is empty.
 | 
				
			||||||
 | 
					  if (wfile && wfile->index_lines.size()) {
 | 
				
			||||||
 | 
					    if (auto line = wfile->GetIndexPosFromBufferPos(
 | 
				
			||||||
 | 
					            ls_pos.line, &ls_pos.character, false)) {
 | 
				
			||||||
 | 
					      ls_pos.line = *line;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      ls_pos.line = -1;
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (auto [sym, refcnt] : file->symbol2refcnt)
 | 
				
			||||||
 | 
					    if (refcnt > 0 && sym.range.Contains(ls_pos.line, ls_pos.character))
 | 
				
			||||||
 | 
					      symbols.push_back(sym);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Order shorter ranges first, since they are more detailed/precise. This is
 | 
				
			||||||
 | 
					  // important for macros which generate code so that we can resolving the
 | 
				
			||||||
 | 
					  // macro argument takes priority over the entire macro body.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Order Kind::Var before Kind::Type. Macro calls are treated as Var
 | 
				
			||||||
 | 
					  // currently. If a macro expands to tokens led by a Kind::Type, the macro and
 | 
				
			||||||
 | 
					  // the Type have the same range. We want to find the macro definition instead
 | 
				
			||||||
 | 
					  // of the Type definition.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // Then order functions before other types, which makes goto definition work
 | 
				
			||||||
 | 
					  // better on constructors.
 | 
				
			||||||
 | 
					  std::sort(
 | 
				
			||||||
 | 
					      symbols.begin(), symbols.end(),
 | 
				
			||||||
 | 
					      [](const SymbolRef &a, const SymbolRef &b) {
 | 
				
			||||||
 | 
					        int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
 | 
				
			||||||
 | 
					        if (t)
 | 
				
			||||||
 | 
					          return t < 0;
 | 
				
			||||||
 | 
					        // MacroExpansion
 | 
				
			||||||
 | 
					        if ((t = (a.role & Role::Dynamic) - (b.role & Role::Dynamic)))
 | 
				
			||||||
 | 
					          return t > 0;
 | 
				
			||||||
 | 
					        if ((t = (a.role & Role::Definition) - (b.role & Role::Definition)))
 | 
				
			||||||
 | 
					          return t > 0;
 | 
				
			||||||
 | 
					        // operator> orders Var/Func before Type.
 | 
				
			||||||
 | 
					        t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
 | 
				
			||||||
 | 
					        if (t)
 | 
				
			||||||
 | 
					          return t > 0;
 | 
				
			||||||
 | 
					        return a.usr < b.usr;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  if (symbols.size() && smallest) {
 | 
				
			||||||
 | 
					    SymbolRef sym = symbols[0];
 | 
				
			||||||
 | 
					    for (size_t i = 1; i < symbols.size(); i++)
 | 
				
			||||||
 | 
					      if (!(sym.range == symbols[i].range && sym.kind == symbols[i].kind)) {
 | 
				
			||||||
 | 
					        symbols.resize(i);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return symbols;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
} // namespace ccls
 | 
					} // namespace ccls
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										84
									
								
								src/query.hh
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								src/query.hh
									
									
									
									
									
								
							@ -17,6 +17,7 @@ limitations under the License.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "indexer.hh"
 | 
					#include "indexer.hh"
 | 
				
			||||||
#include "serializer.hh"
 | 
					#include "serializer.hh"
 | 
				
			||||||
 | 
					#include "working_files.hh"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <llvm/ADT/DenseMap.h>
 | 
					#include <llvm/ADT/DenseMap.h>
 | 
				
			||||||
#include <llvm/ADT/SmallVector.h>
 | 
					#include <llvm/ADT/SmallVector.h>
 | 
				
			||||||
@ -196,4 +197,87 @@ struct DB {
 | 
				
			|||||||
  QueryType &GetType(SymbolIdx ref) { return Type(ref.usr); }
 | 
					  QueryType &GetType(SymbolIdx ref) { return Type(ref.usr); }
 | 
				
			||||||
  QueryVar &GetVar(SymbolIdx ref) { return Var(ref.usr); }
 | 
					  QueryVar &GetVar(SymbolIdx ref) { return Var(ref.usr); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Get defining declaration (if exists) or an arbitrary declaration (otherwise)
 | 
				
			||||||
 | 
					// for each id.
 | 
				
			||||||
 | 
					std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
 | 
				
			||||||
 | 
					std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
 | 
				
			||||||
 | 
					std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Get non-defining declarations.
 | 
				
			||||||
 | 
					std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root);
 | 
				
			||||||
 | 
					std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root);
 | 
				
			||||||
 | 
					std::optional<lsRange> GetLsRange(WorkingFile *working_file,
 | 
				
			||||||
 | 
					                                  const Range &location);
 | 
				
			||||||
 | 
					DocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
 | 
				
			||||||
 | 
					DocumentUri GetLsDocumentUri(DB *db, int file_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use);
 | 
				
			||||||
 | 
					std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
 | 
					                                        SymbolRef sym, int file_id);
 | 
				
			||||||
 | 
					std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
				
			||||||
 | 
					                                           const std::vector<Use> &uses);
 | 
				
			||||||
 | 
					// Returns a symbol. The symbol will *NOT* have a location assigned.
 | 
				
			||||||
 | 
					std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
				
			||||||
 | 
					                                                 bool detailed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
 | 
				
			||||||
 | 
					                                             QueryFile *file,
 | 
				
			||||||
 | 
					                                             Position &ls_pos,
 | 
				
			||||||
 | 
					                                             bool smallest = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Fn> void WithEntity(DB *db, SymbolIdx sym, Fn &&fn) {
 | 
				
			||||||
 | 
					  switch (sym.kind) {
 | 
				
			||||||
 | 
					  case Kind::Invalid:
 | 
				
			||||||
 | 
					  case Kind::File:
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case Kind::Func:
 | 
				
			||||||
 | 
					    fn(db->GetFunc(sym));
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case Kind::Type:
 | 
				
			||||||
 | 
					    fn(db->GetType(sym));
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case Kind::Var:
 | 
				
			||||||
 | 
					    fn(db->GetVar(sym));
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Fn> void EachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
 | 
				
			||||||
 | 
					  WithEntity(db, sym, [&](const auto &entity) {
 | 
				
			||||||
 | 
					    for (auto &def : entity.def)
 | 
				
			||||||
 | 
					      if (!fn(def))
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Fn>
 | 
				
			||||||
 | 
					void EachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
 | 
				
			||||||
 | 
					  WithEntity(db, sym, [&](const auto &entity) {
 | 
				
			||||||
 | 
					    for (Use use : entity.uses)
 | 
				
			||||||
 | 
					      fn(use);
 | 
				
			||||||
 | 
					    if (include_decl) {
 | 
				
			||||||
 | 
					      for (auto &def : entity.def)
 | 
				
			||||||
 | 
					        if (def.spell)
 | 
				
			||||||
 | 
					          fn(*def.spell);
 | 
				
			||||||
 | 
					      for (Use use : entity.declarations)
 | 
				
			||||||
 | 
					        fn(use);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SymbolKind GetSymbolKind(DB *db, SymbolIdx sym);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Fn>
 | 
				
			||||||
 | 
					void EachDefinedFunc(DB *db, const std::vector<Usr> &usrs, Fn &&fn) {
 | 
				
			||||||
 | 
					  for (Usr usr : usrs) {
 | 
				
			||||||
 | 
					    auto &obj = db->Func(usr);
 | 
				
			||||||
 | 
					    if (!obj.def.empty())
 | 
				
			||||||
 | 
					      fn(obj);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
} // namespace ccls
 | 
					} // namespace ccls
 | 
				
			||||||
 | 
				
			|||||||
@ -1,337 +0,0 @@
 | 
				
			|||||||
/* Copyright 2017-2018 ccls Authors
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					 | 
				
			||||||
You may obtain a copy of the License at
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
					 | 
				
			||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					 | 
				
			||||||
See the License for the specific language governing permissions and
 | 
					 | 
				
			||||||
limitations under the License.
 | 
					 | 
				
			||||||
==============================================================================*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "query_utils.hh"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "pipeline.hh"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <limits.h>
 | 
					 | 
				
			||||||
#include <unordered_set>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ccls {
 | 
					 | 
				
			||||||
namespace {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Computes roughly how long |range| is.
 | 
					 | 
				
			||||||
int ComputeRangeSize(const Range &range) {
 | 
					 | 
				
			||||||
  if (range.start.line != range.end.line)
 | 
					 | 
				
			||||||
    return INT_MAX;
 | 
					 | 
				
			||||||
  return range.end.column - range.start.column;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Q>
 | 
					 | 
				
			||||||
std::vector<Use>
 | 
					 | 
				
			||||||
GetDeclarations(llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
 | 
					 | 
				
			||||||
                std::vector<Q> &entities, const std::vector<Usr> &usrs) {
 | 
					 | 
				
			||||||
  std::vector<Use> ret;
 | 
					 | 
				
			||||||
  ret.reserve(usrs.size());
 | 
					 | 
				
			||||||
  for (Usr usr : usrs) {
 | 
					 | 
				
			||||||
    Q &entity = entities[entity_usr[{usr}]];
 | 
					 | 
				
			||||||
    bool has_def = false;
 | 
					 | 
				
			||||||
    for (auto &def : entity.def)
 | 
					 | 
				
			||||||
      if (def.spell) {
 | 
					 | 
				
			||||||
        ret.push_back(*def.spell);
 | 
					 | 
				
			||||||
        has_def = true;
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    if (!has_def && entity.declarations.size())
 | 
					 | 
				
			||||||
      ret.push_back(entity.declarations[0]);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym) {
 | 
					 | 
				
			||||||
  Maybe<DeclRef> ret;
 | 
					 | 
				
			||||||
  EachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.spell); });
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
 | 
					 | 
				
			||||||
  return GetDeclarations(db->func_usr, db->funcs, usrs);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
 | 
					 | 
				
			||||||
  return GetDeclarations(db->type_usr, db->types, usrs);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
std::vector<Use> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
 | 
					 | 
				
			||||||
                                    unsigned kind) {
 | 
					 | 
				
			||||||
  std::vector<Use> ret;
 | 
					 | 
				
			||||||
  ret.reserve(usrs.size());
 | 
					 | 
				
			||||||
  for (Usr usr : usrs) {
 | 
					 | 
				
			||||||
    QueryVar &var = db->Var(usr);
 | 
					 | 
				
			||||||
    bool has_def = false;
 | 
					 | 
				
			||||||
    for (auto &def : var.def)
 | 
					 | 
				
			||||||
      if (def.spell) {
 | 
					 | 
				
			||||||
        has_def = true;
 | 
					 | 
				
			||||||
        // See messages/ccls_vars.cc
 | 
					 | 
				
			||||||
        if (def.kind == SymbolKind::Field) {
 | 
					 | 
				
			||||||
          if (!(kind & 1))
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        } else if (def.kind == SymbolKind::Variable) {
 | 
					 | 
				
			||||||
          if (!(kind & 2))
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        } else if (def.kind == SymbolKind::Parameter) {
 | 
					 | 
				
			||||||
          if (!(kind & 4))
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        ret.push_back(*def.spell);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    if (!has_def && var.declarations.size())
 | 
					 | 
				
			||||||
      ret.push_back(var.declarations[0]);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym) {
 | 
					 | 
				
			||||||
  static std::vector<DeclRef> empty;
 | 
					 | 
				
			||||||
  switch (sym.kind) {
 | 
					 | 
				
			||||||
  case Kind::Func:
 | 
					 | 
				
			||||||
    return db->GetFunc(sym).declarations;
 | 
					 | 
				
			||||||
  case Kind::Type:
 | 
					 | 
				
			||||||
    return db->GetType(sym).declarations;
 | 
					 | 
				
			||||||
  case Kind::Var:
 | 
					 | 
				
			||||||
    return db->GetVar(sym).declarations;
 | 
					 | 
				
			||||||
  default:
 | 
					 | 
				
			||||||
    break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return empty;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {
 | 
					 | 
				
			||||||
  std::vector<Use> ret;
 | 
					 | 
				
			||||||
  std::vector<QueryFunc *> stack{&root};
 | 
					 | 
				
			||||||
  std::unordered_set<Usr> seen;
 | 
					 | 
				
			||||||
  seen.insert(root.usr);
 | 
					 | 
				
			||||||
  while (!stack.empty()) {
 | 
					 | 
				
			||||||
    QueryFunc &func = *stack.back();
 | 
					 | 
				
			||||||
    stack.pop_back();
 | 
					 | 
				
			||||||
    if (auto *def = func.AnyDef()) {
 | 
					 | 
				
			||||||
      EachDefinedFunc(db, def->bases, [&](QueryFunc &func1) {
 | 
					 | 
				
			||||||
        if (!seen.count(func1.usr)) {
 | 
					 | 
				
			||||||
          seen.insert(func1.usr);
 | 
					 | 
				
			||||||
          stack.push_back(&func1);
 | 
					 | 
				
			||||||
          ret.insert(ret.end(), func1.uses.begin(), func1.uses.end());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
 | 
					 | 
				
			||||||
  std::vector<Use> ret;
 | 
					 | 
				
			||||||
  std::vector<QueryFunc *> stack{&root};
 | 
					 | 
				
			||||||
  std::unordered_set<Usr> seen;
 | 
					 | 
				
			||||||
  seen.insert(root.usr);
 | 
					 | 
				
			||||||
  while (!stack.empty()) {
 | 
					 | 
				
			||||||
    QueryFunc &func = *stack.back();
 | 
					 | 
				
			||||||
    stack.pop_back();
 | 
					 | 
				
			||||||
    EachDefinedFunc(db, func.derived, [&](QueryFunc &func1) {
 | 
					 | 
				
			||||||
      if (!seen.count(func1.usr)) {
 | 
					 | 
				
			||||||
        seen.insert(func1.usr);
 | 
					 | 
				
			||||||
        stack.push_back(&func1);
 | 
					 | 
				
			||||||
        ret.insert(ret.end(), func1.uses.begin(), func1.uses.end());
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::optional<lsRange> GetLsRange(WorkingFile *wfile,
 | 
					 | 
				
			||||||
                                  const Range &location) {
 | 
					 | 
				
			||||||
  if (!wfile || wfile->index_lines.empty())
 | 
					 | 
				
			||||||
    return lsRange{Position{location.start.line, location.start.column},
 | 
					 | 
				
			||||||
                   Position{location.end.line, location.end.column}};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int start_column = location.start.column, end_column = location.end.column;
 | 
					 | 
				
			||||||
  std::optional<int> start = wfile->GetBufferPosFromIndexPos(
 | 
					 | 
				
			||||||
      location.start.line, &start_column, false);
 | 
					 | 
				
			||||||
  std::optional<int> end = wfile->GetBufferPosFromIndexPos(
 | 
					 | 
				
			||||||
      location.end.line, &end_column, true);
 | 
					 | 
				
			||||||
  if (!start || !end)
 | 
					 | 
				
			||||||
    return std::nullopt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // If remapping end fails (end can never be < start), just guess that the
 | 
					 | 
				
			||||||
  // final location didn't move. This only screws up the highlighted code
 | 
					 | 
				
			||||||
  // region if we guess wrong, so not a big deal.
 | 
					 | 
				
			||||||
  //
 | 
					 | 
				
			||||||
  // Remapping fails often in C++ since there are a lot of "};" at the end of
 | 
					 | 
				
			||||||
  // class/struct definitions.
 | 
					 | 
				
			||||||
  if (*end < *start)
 | 
					 | 
				
			||||||
    *end = *start + (location.end.line - location.start.line);
 | 
					 | 
				
			||||||
  if (*start == *end && start_column > end_column)
 | 
					 | 
				
			||||||
    end_column = start_column;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return lsRange{Position{*start, start_column}, Position{*end, end_column}};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path) {
 | 
					 | 
				
			||||||
  QueryFile &file = db->files[file_id];
 | 
					 | 
				
			||||||
  if (file.def) {
 | 
					 | 
				
			||||||
    *path = file.def->path;
 | 
					 | 
				
			||||||
    return DocumentUri::FromPath(*path);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    *path = "";
 | 
					 | 
				
			||||||
    return DocumentUri::FromPath("");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DocumentUri GetLsDocumentUri(DB *db, int file_id) {
 | 
					 | 
				
			||||||
  QueryFile &file = db->files[file_id];
 | 
					 | 
				
			||||||
  if (file.def) {
 | 
					 | 
				
			||||||
    return DocumentUri::FromPath(file.def->path);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    return DocumentUri::FromPath("");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use) {
 | 
					 | 
				
			||||||
  std::string path;
 | 
					 | 
				
			||||||
  DocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
 | 
					 | 
				
			||||||
  std::optional<lsRange> range =
 | 
					 | 
				
			||||||
      GetLsRange(wfiles->GetFileByFilename(path), use.range);
 | 
					 | 
				
			||||||
  if (!range)
 | 
					 | 
				
			||||||
    return std::nullopt;
 | 
					 | 
				
			||||||
  return Location{uri, *range};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
					 | 
				
			||||||
                                      SymbolRef sym, int file_id) {
 | 
					 | 
				
			||||||
  return GetLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
					 | 
				
			||||||
                                     const std::vector<Use> &uses) {
 | 
					 | 
				
			||||||
  std::vector<Location> ret;
 | 
					 | 
				
			||||||
  for (Use use : uses)
 | 
					 | 
				
			||||||
    if (auto loc = GetLsLocation(db, wfiles, use))
 | 
					 | 
				
			||||||
      ret.push_back(*loc);
 | 
					 | 
				
			||||||
  std::sort(ret.begin(), ret.end());
 | 
					 | 
				
			||||||
  ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
 | 
					 | 
				
			||||||
  if (ret.size() > g_config->xref.maxNum)
 | 
					 | 
				
			||||||
    ret.resize(g_config->xref.maxNum);
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
 | 
					 | 
				
			||||||
  SymbolKind ret;
 | 
					 | 
				
			||||||
  if (sym.kind == Kind::File)
 | 
					 | 
				
			||||||
    ret = SymbolKind::File;
 | 
					 | 
				
			||||||
  else {
 | 
					 | 
				
			||||||
    ret = SymbolKind::Unknown;
 | 
					 | 
				
			||||||
    WithEntity(db, sym, [&](const auto &entity) {
 | 
					 | 
				
			||||||
      for (auto &def : entity.def) {
 | 
					 | 
				
			||||||
        ret = def.kind;
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
					 | 
				
			||||||
                                               bool detailed) {
 | 
					 | 
				
			||||||
  switch (sym.kind) {
 | 
					 | 
				
			||||||
  case Kind::Invalid:
 | 
					 | 
				
			||||||
    break;
 | 
					 | 
				
			||||||
  case Kind::File: {
 | 
					 | 
				
			||||||
    QueryFile &file = db->GetFile(sym);
 | 
					 | 
				
			||||||
    if (!file.def)
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SymbolInformation info;
 | 
					 | 
				
			||||||
    info.name = file.def->path;
 | 
					 | 
				
			||||||
    info.kind = SymbolKind::File;
 | 
					 | 
				
			||||||
    return info;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  default: {
 | 
					 | 
				
			||||||
    SymbolInformation info;
 | 
					 | 
				
			||||||
    EachEntityDef(db, sym, [&](const auto &def) {
 | 
					 | 
				
			||||||
      if (detailed)
 | 
					 | 
				
			||||||
        info.name = def.detailed_name;
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        info.name = def.Name(true);
 | 
					 | 
				
			||||||
      info.kind = def.kind;
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    return info;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return std::nullopt;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
 | 
					 | 
				
			||||||
                                             QueryFile *file, Position &ls_pos,
 | 
					 | 
				
			||||||
                                             bool smallest) {
 | 
					 | 
				
			||||||
  std::vector<SymbolRef> symbols;
 | 
					 | 
				
			||||||
  // If multiVersion > 0, index may not exist and thus index_lines is empty.
 | 
					 | 
				
			||||||
  if (wfile && wfile->index_lines.size()) {
 | 
					 | 
				
			||||||
    if (auto line = wfile->GetIndexPosFromBufferPos(
 | 
					 | 
				
			||||||
            ls_pos.line, &ls_pos.character, false)) {
 | 
					 | 
				
			||||||
      ls_pos.line = *line;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      ls_pos.line = -1;
 | 
					 | 
				
			||||||
      return {};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (auto [sym, refcnt] : file->symbol2refcnt)
 | 
					 | 
				
			||||||
    if (refcnt > 0 && sym.range.Contains(ls_pos.line, ls_pos.character))
 | 
					 | 
				
			||||||
      symbols.push_back(sym);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Order shorter ranges first, since they are more detailed/precise. This is
 | 
					 | 
				
			||||||
  // important for macros which generate code so that we can resolving the
 | 
					 | 
				
			||||||
  // macro argument takes priority over the entire macro body.
 | 
					 | 
				
			||||||
  //
 | 
					 | 
				
			||||||
  // Order Kind::Var before Kind::Type. Macro calls are treated as Var
 | 
					 | 
				
			||||||
  // currently. If a macro expands to tokens led by a Kind::Type, the macro and
 | 
					 | 
				
			||||||
  // the Type have the same range. We want to find the macro definition instead
 | 
					 | 
				
			||||||
  // of the Type definition.
 | 
					 | 
				
			||||||
  //
 | 
					 | 
				
			||||||
  // Then order functions before other types, which makes goto definition work
 | 
					 | 
				
			||||||
  // better on constructors.
 | 
					 | 
				
			||||||
  std::sort(
 | 
					 | 
				
			||||||
      symbols.begin(), symbols.end(),
 | 
					 | 
				
			||||||
      [](const SymbolRef &a, const SymbolRef &b) {
 | 
					 | 
				
			||||||
        int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
 | 
					 | 
				
			||||||
        if (t)
 | 
					 | 
				
			||||||
          return t < 0;
 | 
					 | 
				
			||||||
        // MacroExpansion
 | 
					 | 
				
			||||||
        if ((t = (a.role & Role::Dynamic) - (b.role & Role::Dynamic)))
 | 
					 | 
				
			||||||
          return t > 0;
 | 
					 | 
				
			||||||
        if ((t = (a.role & Role::Definition) - (b.role & Role::Definition)))
 | 
					 | 
				
			||||||
          return t > 0;
 | 
					 | 
				
			||||||
        // operator> orders Var/Func before Type.
 | 
					 | 
				
			||||||
        t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
 | 
					 | 
				
			||||||
        if (t)
 | 
					 | 
				
			||||||
          return t > 0;
 | 
					 | 
				
			||||||
        return a.usr < b.usr;
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
  if (symbols.size() && smallest) {
 | 
					 | 
				
			||||||
    SymbolRef sym = symbols[0];
 | 
					 | 
				
			||||||
    for (size_t i = 1; i < symbols.size(); i++)
 | 
					 | 
				
			||||||
      if (!(sym.range == symbols[i].range && sym.kind == symbols[i].kind)) {
 | 
					 | 
				
			||||||
        symbols.resize(i);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return symbols;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
} // namespace ccls
 | 
					 | 
				
			||||||
@ -1,106 +0,0 @@
 | 
				
			|||||||
/* Copyright 2017-2018 ccls Authors
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					 | 
				
			||||||
You may obtain a copy of the License at
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  http://www.apache.org/licenses/LICENSE-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Unless required by applicable law or agreed to in writing, software
 | 
					 | 
				
			||||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
					 | 
				
			||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					 | 
				
			||||||
See the License for the specific language governing permissions and
 | 
					 | 
				
			||||||
limitations under the License.
 | 
					 | 
				
			||||||
==============================================================================*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "query.hh"
 | 
					 | 
				
			||||||
#include "working_files.hh"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <optional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ccls {
 | 
					 | 
				
			||||||
Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Get defining declaration (if exists) or an arbitrary declaration (otherwise)
 | 
					 | 
				
			||||||
// for each id.
 | 
					 | 
				
			||||||
std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
 | 
					 | 
				
			||||||
std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
 | 
					 | 
				
			||||||
std::vector<Use> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Get non-defining declarations.
 | 
					 | 
				
			||||||
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root);
 | 
					 | 
				
			||||||
std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root);
 | 
					 | 
				
			||||||
std::optional<lsRange> GetLsRange(WorkingFile *working_file,
 | 
					 | 
				
			||||||
                                  const Range &location);
 | 
					 | 
				
			||||||
DocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
 | 
					 | 
				
			||||||
DocumentUri GetLsDocumentUri(DB *db, int file_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use);
 | 
					 | 
				
			||||||
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
 | 
					 | 
				
			||||||
                                        SymbolRef sym, int file_id);
 | 
					 | 
				
			||||||
std::vector<Location> GetLsLocations(DB *db, WorkingFiles *wfiles,
 | 
					 | 
				
			||||||
                                           const std::vector<Use> &uses);
 | 
					 | 
				
			||||||
// Returns a symbol. The symbol will *NOT* have a location assigned.
 | 
					 | 
				
			||||||
std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
 | 
					 | 
				
			||||||
                                                 bool detailed);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
 | 
					 | 
				
			||||||
                                             QueryFile *file,
 | 
					 | 
				
			||||||
                                             Position &ls_pos,
 | 
					 | 
				
			||||||
                                             bool smallest = false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Fn> void WithEntity(DB *db, SymbolIdx sym, Fn &&fn) {
 | 
					 | 
				
			||||||
  switch (sym.kind) {
 | 
					 | 
				
			||||||
  case Kind::Invalid:
 | 
					 | 
				
			||||||
  case Kind::File:
 | 
					 | 
				
			||||||
    break;
 | 
					 | 
				
			||||||
  case Kind::Func:
 | 
					 | 
				
			||||||
    fn(db->GetFunc(sym));
 | 
					 | 
				
			||||||
    break;
 | 
					 | 
				
			||||||
  case Kind::Type:
 | 
					 | 
				
			||||||
    fn(db->GetType(sym));
 | 
					 | 
				
			||||||
    break;
 | 
					 | 
				
			||||||
  case Kind::Var:
 | 
					 | 
				
			||||||
    fn(db->GetVar(sym));
 | 
					 | 
				
			||||||
    break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Fn> void EachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
 | 
					 | 
				
			||||||
  WithEntity(db, sym, [&](const auto &entity) {
 | 
					 | 
				
			||||||
    for (auto &def : entity.def)
 | 
					 | 
				
			||||||
      if (!fn(def))
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Fn>
 | 
					 | 
				
			||||||
void EachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
 | 
					 | 
				
			||||||
  WithEntity(db, sym, [&](const auto &entity) {
 | 
					 | 
				
			||||||
    for (Use use : entity.uses)
 | 
					 | 
				
			||||||
      fn(use);
 | 
					 | 
				
			||||||
    if (include_decl) {
 | 
					 | 
				
			||||||
      for (auto &def : entity.def)
 | 
					 | 
				
			||||||
        if (def.spell)
 | 
					 | 
				
			||||||
          fn(*def.spell);
 | 
					 | 
				
			||||||
      for (Use use : entity.declarations)
 | 
					 | 
				
			||||||
        fn(use);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Fn>
 | 
					 | 
				
			||||||
void EachDefinedFunc(DB *db, const std::vector<Usr> &usrs, Fn &&fn) {
 | 
					 | 
				
			||||||
  for (Usr usr : usrs) {
 | 
					 | 
				
			||||||
    auto &obj = db->Func(usr);
 | 
					 | 
				
			||||||
    if (!obj.def.empty())
 | 
					 | 
				
			||||||
      fn(obj);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
} // namespace ccls
 | 
					 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user