diagnostic_emitter.cpp 4.9 KB

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