diagnostic_emitter.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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 <optional>
  7. #include <string>
  8. #include "common/raw_string_ostream.h"
  9. #include "toolchain/check/diagnostic_helpers.h"
  10. #include "toolchain/sem_ir/absolute_node_id.h"
  11. #include "toolchain/sem_ir/ids.h"
  12. #include "toolchain/sem_ir/stringify.h"
  13. namespace Carbon::Check {
  14. auto DiagnosticEmitter::ConvertLoc(LocIdForDiagnostics loc_id,
  15. ContextFnT context_fn) const
  16. -> Diagnostics::ConvertedLoc {
  17. auto [imports, converted] = loc_converter_.ConvertWithImports(
  18. loc_id.loc_id(), loc_id.is_token_only());
  19. for (const auto& import : imports) {
  20. CARBON_DIAGNOSTIC(InImport, LocationInfo, "in import");
  21. context_fn(import.loc, InImport);
  22. }
  23. // Use the token when possible, but -1 is the default value.
  24. auto last_offset = -1;
  25. if (last_token_.has_value()) {
  26. last_offset = sem_ir_->parse_tree().tokens().GetByteOffset(last_token_);
  27. }
  28. // When the diagnostic is in the same file, we use the last possible offset;
  29. // otherwise, we ignore the offset because it's probably in that file.
  30. if (converted.loc.filename == sem_ir_->filename()) {
  31. converted.last_byte_offset =
  32. std::max(converted.last_byte_offset, last_offset);
  33. } else {
  34. converted.last_byte_offset = last_offset;
  35. }
  36. return converted;
  37. }
  38. auto DiagnosticEmitter::ConvertArg(llvm::Any arg) const -> llvm::Any {
  39. if (auto* library_name_id = llvm::any_cast<SemIR::LibraryNameId>(&arg)) {
  40. std::string library_name;
  41. if (*library_name_id == SemIR::LibraryNameId::Default) {
  42. library_name = "default library";
  43. } else if (!library_name_id->has_value()) {
  44. library_name = "library <none>";
  45. } else {
  46. RawStringOstream stream;
  47. stream << "library \""
  48. << sem_ir_->string_literal_values().Get(
  49. library_name_id->AsStringLiteralValueId())
  50. << "\"";
  51. library_name = stream.TakeStr();
  52. }
  53. return library_name;
  54. }
  55. if (auto* name_id = llvm::any_cast<SemIR::NameId>(&arg)) {
  56. return sem_ir_->names().GetFormatted(*name_id).str();
  57. }
  58. if (auto* type_of_expr = llvm::any_cast<TypeOfInstId>(&arg)) {
  59. if (!type_of_expr->inst_id.has_value()) {
  60. return "<none>";
  61. }
  62. // TODO: Where possible, produce a better description of the type based on
  63. // the expression.
  64. return "`" +
  65. StringifyConstantInst(
  66. *sem_ir_,
  67. sem_ir_->types().GetInstId(
  68. sem_ir_->insts().Get(type_of_expr->inst_id).type_id())) +
  69. "`";
  70. }
  71. if (auto* expr = llvm::any_cast<InstIdAsConstant>(&arg)) {
  72. return "`" + StringifyConstantInst(*sem_ir_, expr->inst_id) + "`";
  73. }
  74. if (auto* type_expr = llvm::any_cast<InstIdAsRawType>(&arg)) {
  75. return StringifyConstantInst(*sem_ir_, type_expr->inst_id);
  76. }
  77. if (auto* type = llvm::any_cast<TypeIdAsRawType>(&arg)) {
  78. return StringifyConstantInst(*sem_ir_,
  79. sem_ir_->types().GetInstId(type->type_id));
  80. }
  81. if (auto* type_id = llvm::any_cast<SemIR::TypeId>(&arg)) {
  82. return "`" +
  83. StringifyConstantInst(*sem_ir_,
  84. sem_ir_->types().GetInstId(*type_id)) +
  85. "`";
  86. }
  87. if (auto* specific_id = llvm::any_cast<SemIR::SpecificId>(&arg)) {
  88. return "`" + StringifySpecific(*sem_ir_, *specific_id) + "`";
  89. }
  90. if (auto* typed_int = llvm::any_cast<TypedInt>(&arg)) {
  91. return llvm::APSInt(typed_int->value,
  92. !sem_ir_->types().IsSignedInt(typed_int->type));
  93. }
  94. if (auto* specific_interface_id =
  95. llvm::any_cast<SemIR::SpecificInterfaceId>(&arg)) {
  96. auto specific_interface =
  97. sem_ir_->specific_interfaces().Get(*specific_interface_id);
  98. return "`" + StringifySpecificInterface(*sem_ir_, specific_interface) + "`";
  99. }
  100. if (auto* specific_interface_raw =
  101. llvm::any_cast<SpecificInterfaceIdAsRawType>(&arg)) {
  102. auto specific_interface = sem_ir_->specific_interfaces().Get(
  103. specific_interface_raw->specific_interface_id);
  104. return StringifySpecificInterface(*sem_ir_, specific_interface);
  105. }
  106. return DiagnosticEmitterBase::ConvertArg(arg);
  107. }
  108. } // namespace Carbon::Check