absolute_node_id.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/sem_ir/absolute_node_id.h"
  5. #include "toolchain/sem_ir/ids.h"
  6. namespace Carbon::SemIR {
  7. // Follows an imported instruction location to find the sequence of import
  8. // locations and the ultimately imported location.
  9. static auto FollowImportRef(
  10. llvm::SmallVector<AbsoluteNodeId>& absolute_node_ids,
  11. const File*& cursor_ir, InstId& cursor_inst_id,
  12. ImportIRInstId import_ir_inst_id) -> bool {
  13. auto import_ir_inst = cursor_ir->import_ir_insts().Get(import_ir_inst_id);
  14. if (import_ir_inst.ir_id() == ImportIRId::Cpp) {
  15. CARBON_CHECK(cursor_ir->import_cpps().size() > 0);
  16. // TODO: Decompose the Clang source location to determine which C++ import
  17. // made this location available, and use the location of that import instead
  18. // of arbitrarily using the first C++ import.
  19. absolute_node_ids.push_back(
  20. AbsoluteNodeId(cursor_ir->check_ir_id(),
  21. cursor_ir->import_cpps().values().begin()->node_id));
  22. absolute_node_ids.push_back(
  23. AbsoluteNodeId(import_ir_inst.clang_source_loc_id()));
  24. return true;
  25. }
  26. const auto& import_ir = cursor_ir->import_irs().Get(import_ir_inst.ir_id());
  27. CARBON_CHECK(import_ir.decl_id.has_value(),
  28. "If we get `None` locations here, we may need to more "
  29. "thoroughly track ImportDecls.");
  30. auto import_loc_id = cursor_ir->insts().GetCanonicalLocId(import_ir.decl_id);
  31. switch (import_loc_id.kind()) {
  32. case LocId::Kind::None:
  33. break;
  34. case LocId::Kind::ImportIRInstId: {
  35. // For implicit imports, we need to unravel the location a little
  36. // further.
  37. auto implicit_import_ir_inst =
  38. cursor_ir->import_ir_insts().Get(import_loc_id.import_ir_inst_id());
  39. const auto& implicit_ir =
  40. cursor_ir->import_irs().Get(implicit_import_ir_inst.ir_id());
  41. auto implicit_loc_id = implicit_ir.sem_ir->insts().GetCanonicalLocId(
  42. implicit_import_ir_inst.inst_id());
  43. CARBON_CHECK(implicit_loc_id.kind() == LocId::Kind::NodeId,
  44. "Should only be one layer of implicit imports");
  45. absolute_node_ids.push_back(AbsoluteNodeId(
  46. implicit_ir.sem_ir->check_ir_id(), implicit_loc_id.node_id()));
  47. break;
  48. }
  49. case LocId::Kind::InstId:
  50. CARBON_FATAL("Unexpected LocId: {0}", import_loc_id);
  51. case LocId::Kind::NodeId: {
  52. // For imports in the current file, the location is simple.
  53. absolute_node_ids.push_back(
  54. AbsoluteNodeId(cursor_ir->check_ir_id(), import_loc_id.node_id()));
  55. break;
  56. }
  57. }
  58. cursor_ir = import_ir.sem_ir;
  59. cursor_inst_id = import_ir_inst.inst_id();
  60. return false;
  61. }
  62. // Returns true if this is the final parse node location. If the location is an
  63. // import, follows it and returns false.
  64. static auto HandleLocId(llvm::SmallVector<AbsoluteNodeId>& absolute_node_ids,
  65. const File*& cursor_ir, InstId& cursor_inst_id,
  66. LocId loc_id) -> bool {
  67. switch (loc_id.kind()) {
  68. case LocId::Kind::ImportIRInstId: {
  69. return FollowImportRef(absolute_node_ids, cursor_ir, cursor_inst_id,
  70. loc_id.import_ir_inst_id());
  71. }
  72. case LocId::Kind::NodeId: {
  73. // Parse nodes always refer to the current IR.
  74. absolute_node_ids.push_back(
  75. AbsoluteNodeId(cursor_ir->check_ir_id(), loc_id.node_id()));
  76. return true;
  77. }
  78. case LocId::Kind::None:
  79. case LocId::Kind::InstId:
  80. CARBON_FATAL("Unexpected LocId: {0}", loc_id);
  81. }
  82. }
  83. // Loops through imported instructions until the actual instruction is found.
  84. static auto GetAbsoluteNodeIdImpl(
  85. llvm::SmallVector<AbsoluteNodeId>& absolute_node_ids, const File* cursor_ir,
  86. InstId cursor_inst_id) -> void {
  87. while (cursor_inst_id.has_value()) {
  88. auto cursor_inst = cursor_ir->insts().Get(cursor_inst_id);
  89. if (auto bind_ref = cursor_inst.TryAs<ExportDecl>();
  90. bind_ref && bind_ref->value_id.has_value()) {
  91. cursor_inst_id = bind_ref->value_id;
  92. continue;
  93. }
  94. // If the parse node has a value, use it for the location.
  95. if (auto loc_id = cursor_ir->insts().GetCanonicalLocId(cursor_inst_id);
  96. loc_id.has_value()) {
  97. if (HandleLocId(absolute_node_ids, cursor_ir, cursor_inst_id, loc_id)) {
  98. return;
  99. }
  100. continue;
  101. }
  102. // If a namespace has an instruction for an import, switch to looking at it.
  103. if (auto ns = cursor_inst.TryAs<Namespace>()) {
  104. if (ns->import_id.has_value()) {
  105. cursor_inst_id = ns->import_id;
  106. continue;
  107. }
  108. }
  109. break;
  110. }
  111. // `None` parse node but not an import; just nothing to point at.
  112. absolute_node_ids.push_back(
  113. AbsoluteNodeId(cursor_ir->check_ir_id(), Parse::NodeId::None));
  114. }
  115. auto GetAbsoluteNodeId(const File* sem_ir, LocId loc_id)
  116. -> llvm::SmallVector<AbsoluteNodeId> {
  117. llvm::SmallVector<AbsoluteNodeId> absolute_node_ids;
  118. switch (loc_id.kind()) {
  119. case LocId::Kind::None:
  120. absolute_node_ids.push_back(
  121. AbsoluteNodeId(sem_ir->check_ir_id(), Parse::NodeId::None));
  122. break;
  123. case LocId::Kind::InstId:
  124. GetAbsoluteNodeIdImpl(absolute_node_ids, sem_ir, loc_id.inst_id());
  125. break;
  126. case LocId::Kind::ImportIRInstId:
  127. case LocId::Kind::NodeId: {
  128. const File* cursor_ir = sem_ir;
  129. InstId cursor_inst_id = InstId::None;
  130. if (HandleLocId(absolute_node_ids, cursor_ir, cursor_inst_id,
  131. cursor_ir->insts().GetCanonicalLocId(loc_id))) {
  132. break;
  133. }
  134. CARBON_CHECK(cursor_inst_id.has_value(), "Should be set by HandleLocId");
  135. GetAbsoluteNodeIdImpl(absolute_node_ids, cursor_ir, cursor_inst_id);
  136. break;
  137. }
  138. }
  139. return absolute_node_ids;
  140. }
  141. } // namespace Carbon::SemIR