sem_ir_diagnostic_converter.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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/check/sem_ir_diagnostic_converter.h"
  5. #include "common/raw_string_ostream.h"
  6. #include "toolchain/sem_ir/absolute_node_id.h"
  7. #include "toolchain/sem_ir/stringify_type.h"
  8. namespace Carbon::Check {
  9. auto SemIRDiagnosticConverter::ConvertLoc(SemIRLoc loc,
  10. ContextFnT context_fn) const
  11. -> ConvertedDiagnosticLoc {
  12. auto converted = ConvertLocImpl(loc, context_fn);
  13. // Use the token when possible, but -1 is the default value.
  14. auto last_offset = -1;
  15. if (last_token_.has_value()) {
  16. last_offset = sem_ir_->parse_tree().tokens().GetByteOffset(last_token_);
  17. }
  18. // When the diagnostic is in the same file, we use the last possible offset;
  19. // otherwise, we ignore the offset because it's probably in that file.
  20. if (converted.loc.filename == sem_ir_->filename()) {
  21. converted.last_byte_offset =
  22. std::max(converted.last_byte_offset, last_offset);
  23. } else {
  24. converted.last_byte_offset = last_offset;
  25. }
  26. return converted;
  27. }
  28. auto SemIRDiagnosticConverter::ConvertLocImpl(SemIRLoc loc,
  29. ContextFnT context_fn) const
  30. -> ConvertedDiagnosticLoc {
  31. llvm::SmallVector<SemIR::AbsoluteNodeId> absolute_node_ids =
  32. loc.is_inst_id_ ? SemIR::GetAbsoluteNodeId(sem_ir_, loc.inst_id_)
  33. : SemIR::GetAbsoluteNodeId(sem_ir_, loc.loc_id_);
  34. auto final_node_id = absolute_node_ids.pop_back_val();
  35. for (const auto& absolute_node_id : absolute_node_ids) {
  36. if (!absolute_node_id.node_id.has_value()) {
  37. // TODO: Add an "In implicit import of prelude." note for the case where
  38. // we don't have a location.
  39. continue;
  40. }
  41. // TODO: Include the name of the imported library in the diagnostic.
  42. auto diag_loc =
  43. ConvertLocInFile(absolute_node_id, loc.token_only_, context_fn);
  44. CARBON_DIAGNOSTIC(InImport, LocationInfo, "in import");
  45. context_fn(diag_loc.loc, InImport);
  46. }
  47. return ConvertLocInFile(final_node_id, loc.token_only_, context_fn);
  48. }
  49. auto SemIRDiagnosticConverter::ConvertLocInFile(
  50. SemIR::AbsoluteNodeId absolute_node_id, bool token_only,
  51. ContextFnT /*context_fn*/) const -> ConvertedDiagnosticLoc {
  52. const auto& tree_and_subtrees =
  53. imported_trees_and_subtrees_[absolute_node_id.check_ir_id.index]();
  54. return tree_and_subtrees.NodeToDiagnosticLoc(absolute_node_id.node_id,
  55. token_only);
  56. }
  57. auto SemIRDiagnosticConverter::ConvertArg(llvm::Any arg) const -> llvm::Any {
  58. if (auto* library_name_id = llvm::any_cast<SemIR::LibraryNameId>(&arg)) {
  59. std::string library_name;
  60. if (*library_name_id == SemIR::LibraryNameId::Default) {
  61. library_name = "default library";
  62. } else if (!library_name_id->has_value()) {
  63. library_name = "library <none>";
  64. } else {
  65. RawStringOstream stream;
  66. stream << "library \""
  67. << sem_ir_->string_literal_values().Get(
  68. library_name_id->AsStringLiteralValueId())
  69. << "\"";
  70. library_name = stream.TakeStr();
  71. }
  72. return library_name;
  73. }
  74. if (auto* name_id = llvm::any_cast<SemIR::NameId>(&arg)) {
  75. return sem_ir_->names().GetFormatted(*name_id).str();
  76. }
  77. if (auto* type_of_expr = llvm::any_cast<TypeOfInstId>(&arg)) {
  78. if (!type_of_expr->inst_id.has_value()) {
  79. return "<none>";
  80. }
  81. // TODO: Where possible, produce a better description of the type based on
  82. // the expression.
  83. return "`" +
  84. StringifyTypeExpr(
  85. *sem_ir_,
  86. sem_ir_->types().GetInstId(
  87. sem_ir_->insts().Get(type_of_expr->inst_id).type_id())) +
  88. "`";
  89. }
  90. if (auto* type_expr = llvm::any_cast<InstIdAsType>(&arg)) {
  91. return "`" + StringifyTypeExpr(*sem_ir_, type_expr->inst_id) + "`";
  92. }
  93. if (auto* type_expr = llvm::any_cast<InstIdAsRawType>(&arg)) {
  94. return StringifyTypeExpr(*sem_ir_, type_expr->inst_id);
  95. }
  96. if (auto* type = llvm::any_cast<TypeIdAsRawType>(&arg)) {
  97. return StringifyTypeExpr(*sem_ir_,
  98. sem_ir_->types().GetInstId(type->type_id));
  99. }
  100. if (auto* type_id = llvm::any_cast<SemIR::TypeId>(&arg)) {
  101. return "`" +
  102. StringifyTypeExpr(*sem_ir_, sem_ir_->types().GetInstId(*type_id)) +
  103. "`";
  104. }
  105. if (auto* typed_int = llvm::any_cast<TypedInt>(&arg)) {
  106. return llvm::APSInt(typed_int->value,
  107. !sem_ir_->types().IsSignedInt(typed_int->type));
  108. }
  109. return DiagnosticConverter<SemIRLoc>::ConvertArg(arg);
  110. }
  111. } // namespace Carbon::Check