mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:00:11 +01:00
Rename DiagnosticLocationTranslator -> DiagnosticConverter (#3804)
Since the addition of TranslateArg, I don't think this type is going to go away (cutting a TODO). Refactoring names slightly to fit the current role, and adding const to ConvertLocation.
This commit is contained in:
@@ -82,7 +82,7 @@ cc_library(
|
||||
"//toolchain/lex:tokenized_buffer",
|
||||
"//toolchain/parse:node_kind",
|
||||
"//toolchain/parse:tree",
|
||||
"//toolchain/parse:tree_node_location_translator",
|
||||
"//toolchain/parse:tree_node_diagnostic_converter",
|
||||
"//toolchain/sem_ir:builtin_kind",
|
||||
"//toolchain/sem_ir:file",
|
||||
"//toolchain/sem_ir:ids",
|
||||
@@ -119,7 +119,7 @@ cc_library(
|
||||
"//toolchain/lex:tokenized_buffer",
|
||||
"//toolchain/parse:node_kind",
|
||||
"//toolchain/parse:tree",
|
||||
"//toolchain/parse:tree_node_location_translator",
|
||||
"//toolchain/parse:tree_node_diagnostic_converter",
|
||||
"//toolchain/sem_ir:entry_point",
|
||||
"//toolchain/sem_ir:file",
|
||||
"//toolchain/sem_ir:ids",
|
||||
|
||||
+35
-38
@@ -12,7 +12,7 @@
|
||||
#include "toolchain/lex/token_kind.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/parse/tree.h"
|
||||
#include "toolchain/parse/tree_node_location_translator.h"
|
||||
#include "toolchain/parse/tree_node_diagnostic_converter.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
@@ -25,19 +25,18 @@ namespace Carbon::Check {
|
||||
#include "toolchain/parse/node_kind.def"
|
||||
|
||||
// Handles the transformation of a SemIRLocation to a DiagnosticLocation.
|
||||
class SemIRLocationTranslator
|
||||
: public DiagnosticLocationTranslator<SemIRLocation> {
|
||||
class SemIRDiagnosticConverter : public DiagnosticConverter<SemIRLocation> {
|
||||
public:
|
||||
explicit SemIRLocationTranslator(
|
||||
const llvm::DenseMap<const SemIR::File*, Parse::NodeLocationTranslator*>*
|
||||
node_translators,
|
||||
explicit SemIRDiagnosticConverter(
|
||||
const llvm::DenseMap<const SemIR::File*, Parse::NodeLocationConverter*>*
|
||||
node_converters,
|
||||
const SemIR::File* sem_ir)
|
||||
: node_translators_(node_translators), sem_ir_(sem_ir) {}
|
||||
: node_converters_(node_converters), sem_ir_(sem_ir) {}
|
||||
|
||||
auto GetLocation(SemIRLocation loc) -> DiagnosticLocation override {
|
||||
auto ConvertLocation(SemIRLocation loc) const -> DiagnosticLocation override {
|
||||
// Parse nodes always refer to the current IR.
|
||||
if (!loc.is_inst_id) {
|
||||
return GetLocationInFile(sem_ir_, loc.node_location);
|
||||
return ConvertLocationInFile(sem_ir_, loc.node_location);
|
||||
}
|
||||
|
||||
const auto* cursor_ir = sem_ir_;
|
||||
@@ -46,7 +45,7 @@ class SemIRLocationTranslator
|
||||
// If the parse node is valid, use it for the location.
|
||||
if (auto node_id = cursor_ir->insts().GetNodeId(cursor_inst_id);
|
||||
node_id.is_valid()) {
|
||||
return GetLocationInFile(cursor_ir, node_id);
|
||||
return ConvertLocationInFile(cursor_ir, node_id);
|
||||
}
|
||||
|
||||
// If the parse node was invalid, recurse through import references when
|
||||
@@ -69,38 +68,37 @@ class SemIRLocationTranslator
|
||||
}
|
||||
|
||||
// Invalid parse node but not an import; just nothing to point at.
|
||||
return GetLocationInFile(cursor_ir, Parse::NodeId::Invalid);
|
||||
return ConvertLocationInFile(cursor_ir, Parse::NodeId::Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
auto TranslateArg(DiagnosticTypeTranslation translation, llvm::Any arg) const
|
||||
auto ConvertArg(DiagnosticTypeConversion conversion, llvm::Any arg) const
|
||||
-> llvm::Any override {
|
||||
switch (translation) {
|
||||
case DiagnosticTypeTranslation::NameId: {
|
||||
switch (conversion) {
|
||||
case DiagnosticTypeConversion::NameId: {
|
||||
auto name_id = llvm::any_cast<SemIR::NameId>(arg);
|
||||
return sem_ir_->names().GetFormatted(name_id).str();
|
||||
}
|
||||
case DiagnosticTypeTranslation::TypeId: {
|
||||
case DiagnosticTypeConversion::TypeId: {
|
||||
auto type_id = llvm::any_cast<SemIR::TypeId>(arg);
|
||||
return sem_ir_->StringifyType(type_id);
|
||||
}
|
||||
default:
|
||||
return DiagnosticLocationTranslator<SemIRLocation>::TranslateArg(
|
||||
translation, arg);
|
||||
return DiagnosticConverter<SemIRLocation>::ConvertArg(conversion, arg);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetLocationInFile(const SemIR::File* sem_ir,
|
||||
Parse::NodeLocation node_location) const
|
||||
auto ConvertLocationInFile(const SemIR::File* sem_ir,
|
||||
Parse::NodeLocation node_location) const
|
||||
-> DiagnosticLocation {
|
||||
auto it = node_translators_->find(sem_ir);
|
||||
CARBON_CHECK(it != node_translators_->end());
|
||||
return it->second->GetLocation(node_location);
|
||||
auto it = node_converters_->find(sem_ir);
|
||||
CARBON_CHECK(it != node_converters_->end());
|
||||
return it->second->ConvertLocation(node_location);
|
||||
}
|
||||
|
||||
const llvm::DenseMap<const SemIR::File*, Parse::NodeLocationTranslator*>*
|
||||
node_translators_;
|
||||
const llvm::DenseMap<const SemIR::File*, Parse::NodeLocationConverter*>*
|
||||
node_converters_;
|
||||
const SemIR::File* sem_ir_;
|
||||
};
|
||||
|
||||
@@ -129,15 +127,15 @@ struct UnitInfo {
|
||||
|
||||
explicit UnitInfo(Unit& unit)
|
||||
: unit(&unit),
|
||||
translator(unit.tokens, unit.tokens->source().filename(),
|
||||
unit.parse_tree),
|
||||
converter(unit.tokens, unit.tokens->source().filename(),
|
||||
unit.parse_tree),
|
||||
err_tracker(*unit.consumer),
|
||||
emitter(translator, err_tracker) {}
|
||||
emitter(converter, err_tracker) {}
|
||||
|
||||
Unit* unit;
|
||||
|
||||
// Emitter information.
|
||||
Parse::NodeLocationTranslator translator;
|
||||
Parse::NodeLocationConverter converter;
|
||||
ErrorTrackingDiagnosticConsumer err_tracker;
|
||||
DiagnosticEmitter<Parse::NodeLocation> emitter;
|
||||
|
||||
@@ -255,8 +253,8 @@ static auto ProcessNodeIds(Context& context,
|
||||
|
||||
// Produces and checks the IR for the provided Parse::Tree.
|
||||
static auto CheckParseTree(
|
||||
llvm::DenseMap<const SemIR::File*, Parse::NodeLocationTranslator*>*
|
||||
node_translators,
|
||||
llvm::DenseMap<const SemIR::File*, Parse::NodeLocationConverter*>*
|
||||
node_converters,
|
||||
const SemIR::File& builtin_ir, UnitInfo& unit_info,
|
||||
llvm::raw_ostream* vlog_stream) -> void {
|
||||
unit_info.unit->sem_ir->emplace(
|
||||
@@ -265,11 +263,10 @@ static auto CheckParseTree(
|
||||
|
||||
// For ease-of-access.
|
||||
SemIR::File& sem_ir = **unit_info.unit->sem_ir;
|
||||
CARBON_CHECK(
|
||||
node_translators->insert({&sem_ir, &unit_info.translator}).second);
|
||||
CARBON_CHECK(node_converters->insert({&sem_ir, &unit_info.converter}).second);
|
||||
|
||||
SemIRLocationTranslator translator(node_translators, &sem_ir);
|
||||
Context::DiagnosticEmitter emitter(translator, unit_info.err_tracker);
|
||||
SemIRDiagnosticConverter converter(node_converters, &sem_ir);
|
||||
Context::DiagnosticEmitter emitter(converter, unit_info.err_tracker);
|
||||
Context context(*unit_info.unit->tokens, emitter, *unit_info.unit->parse_tree,
|
||||
sem_ir, vlog_stream);
|
||||
PrettyStackTraceFunction context_dumper(
|
||||
@@ -582,15 +579,15 @@ auto CheckParseTrees(const SemIR::File& builtin_ir,
|
||||
}
|
||||
}
|
||||
|
||||
llvm::DenseMap<const SemIR::File*, Parse::NodeLocationTranslator*>
|
||||
node_translators;
|
||||
llvm::DenseMap<const SemIR::File*, Parse::NodeLocationConverter*>
|
||||
node_converters;
|
||||
|
||||
// Check everything with no dependencies. Earlier entries with dependencies
|
||||
// will be checked as soon as all their dependencies have been checked.
|
||||
for (int check_index = 0;
|
||||
check_index < static_cast<int>(ready_to_check.size()); ++check_index) {
|
||||
auto* unit_info = ready_to_check[check_index];
|
||||
CheckParseTree(&node_translators, builtin_ir, *unit_info, vlog_stream);
|
||||
CheckParseTree(&node_converters, builtin_ir, *unit_info, vlog_stream);
|
||||
for (auto* incoming_import : unit_info->incoming_imports) {
|
||||
--incoming_import->imports_remaining;
|
||||
if (incoming_import->imports_remaining == 0) {
|
||||
@@ -635,7 +632,7 @@ auto CheckParseTrees(const SemIR::File& builtin_ir,
|
||||
// incomplete imports.
|
||||
for (auto& unit_info : unit_infos) {
|
||||
if (unit_info.imports_remaining > 0) {
|
||||
CheckParseTree(&node_translators, builtin_ir, unit_info, vlog_stream);
|
||||
CheckParseTree(&node_converters, builtin_ir, unit_info, vlog_stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "toolchain/check/scope_stack.h"
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/parse/tree.h"
|
||||
#include "toolchain/parse/tree_node_location_translator.h"
|
||||
#include "toolchain/parse/tree_node_diagnostic_converter.h"
|
||||
#include "toolchain/sem_ir/file.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "toolchain/check/function.h"
|
||||
#include "toolchain/check/interface.h"
|
||||
#include "toolchain/check/modifiers.h"
|
||||
#include "toolchain/parse/tree_node_location_translator.h"
|
||||
#include "toolchain/parse/tree_node_diagnostic_converter.h"
|
||||
#include "toolchain/sem_ir/entry_point.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
@@ -17,8 +17,8 @@ cc_library(
|
||||
hdrs = [
|
||||
"diagnostic.h",
|
||||
"diagnostic_consumer.h",
|
||||
"diagnostic_converter.h",
|
||||
"diagnostic_emitter.h",
|
||||
"diagnostic_translator.h",
|
||||
],
|
||||
deps = [
|
||||
":diagnostic_kind",
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONVERTER_H_
|
||||
#define CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONVERTER_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "common/check.h"
|
||||
#include "llvm/ADT/Any.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
// Known diagnostic type conversions. These are enumerated because `llvm::Any`
|
||||
// doesn't expose the contained type; instead, we infer it from a given
|
||||
// diagnostic.
|
||||
enum class DiagnosticTypeConversion : int8_t {
|
||||
None,
|
||||
NameId,
|
||||
TypeId,
|
||||
};
|
||||
|
||||
// An interface that can convert some representation of a location into a
|
||||
// diagnostic location.
|
||||
template <typename LocationT>
|
||||
class DiagnosticConverter {
|
||||
public:
|
||||
virtual ~DiagnosticConverter() = default;
|
||||
|
||||
virtual auto ConvertLocation(LocationT loc) const -> DiagnosticLocation = 0;
|
||||
|
||||
// Converts arg types as needed. Not all uses support conversion, so the
|
||||
// default simply errors.
|
||||
virtual auto ConvertArg(DiagnosticTypeConversion conversion,
|
||||
llvm::Any /*arg*/) const -> llvm::Any {
|
||||
CARBON_FATAL() << "Unexpected call to ConvertArg: "
|
||||
<< static_cast<int8_t>(conversion);
|
||||
}
|
||||
};
|
||||
|
||||
// Used by types to indicate a DiagnosticTypeConversion that results in the
|
||||
// provided StorageType. For example, to convert NameId to a std::string, we
|
||||
// write:
|
||||
//
|
||||
// struct NameId {
|
||||
// using DiagnosticType =
|
||||
// DiagnosticTypeInfo<std::string, DiagnosticTypeConversion::NameId>;
|
||||
// };
|
||||
template <typename StorageTypeT, DiagnosticTypeConversion ConversionV>
|
||||
struct DiagnosticTypeInfo {
|
||||
using StorageType = StorageTypeT;
|
||||
static constexpr DiagnosticTypeConversion Conversion = ConversionV;
|
||||
};
|
||||
|
||||
namespace Internal {
|
||||
|
||||
// Determines whether there's a DiagnosticType member on Arg.
|
||||
// Used by DiagnosticEmitter.
|
||||
template <typename Arg>
|
||||
concept HasDiagnosticType =
|
||||
requires { std::type_identity<typename Arg::DiagnosticType>(); };
|
||||
|
||||
// The default implementation with no conversion.
|
||||
template <typename Arg, typename /*Unused*/ = void>
|
||||
struct DiagnosticTypeForArg
|
||||
: public DiagnosticTypeInfo<Arg, DiagnosticTypeConversion::None> {};
|
||||
|
||||
// Exposes a custom conversion for an argument type.
|
||||
template <typename Arg>
|
||||
requires HasDiagnosticType<Arg>
|
||||
struct DiagnosticTypeForArg<Arg> : public Arg::DiagnosticType {};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONVERTER_H_
|
||||
@@ -16,8 +16,8 @@
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
#include "toolchain/diagnostics/diagnostic_consumer.h"
|
||||
#include "toolchain/diagnostics/diagnostic_converter.h"
|
||||
#include "toolchain/diagnostics/diagnostic_kind.h"
|
||||
#include "toolchain/diagnostics/diagnostic_translator.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
@@ -103,7 +103,7 @@ class DiagnosticEmitter {
|
||||
const Internal::DiagnosticBase<Args...>& diagnostic_base,
|
||||
llvm::SmallVector<llvm::Any> args) -> DiagnosticMessage {
|
||||
return DiagnosticMessage(
|
||||
diagnostic_base.Kind, emitter->translator_->GetLocation(location),
|
||||
diagnostic_base.Kind, emitter->converter_->ConvertLocation(location),
|
||||
diagnostic_base.Format, std::move(args),
|
||||
[](const DiagnosticMessage& message) -> std::string {
|
||||
return FormatFn<Args...>(
|
||||
@@ -131,12 +131,11 @@ class DiagnosticEmitter {
|
||||
Diagnostic diagnostic_;
|
||||
};
|
||||
|
||||
// The `translator` and `consumer` are required to outlive the diagnostic
|
||||
// The `converter` and `consumer` are required to outlive the diagnostic
|
||||
// emitter.
|
||||
explicit DiagnosticEmitter(
|
||||
DiagnosticLocationTranslator<LocationT>& translator,
|
||||
DiagnosticConsumer& consumer)
|
||||
: translator_(&translator), consumer_(&consumer) {}
|
||||
explicit DiagnosticEmitter(DiagnosticConverter<LocationT>& converter,
|
||||
DiagnosticConsumer& consumer)
|
||||
: converter_(&converter), consumer_(&consumer) {}
|
||||
~DiagnosticEmitter() = default;
|
||||
|
||||
// Emits an error.
|
||||
@@ -167,22 +166,22 @@ class DiagnosticEmitter {
|
||||
|
||||
private:
|
||||
// Converts an argument to llvm::Any for storage, handling input to storage
|
||||
// type translation when needed.
|
||||
// type conversion when needed.
|
||||
template <typename Arg>
|
||||
auto MakeAny(Arg arg) -> llvm::Any {
|
||||
if constexpr (Internal::DiagnosticTypeForArg<Arg>::Translation ==
|
||||
DiagnosticTypeTranslation::None) {
|
||||
if constexpr (Internal::DiagnosticTypeForArg<Arg>::Conversion ==
|
||||
DiagnosticTypeConversion::None) {
|
||||
return arg;
|
||||
} else {
|
||||
return translator_->TranslateArg(
|
||||
Internal::DiagnosticTypeForArg<Arg>::Translation, arg);
|
||||
return converter_->ConvertArg(
|
||||
Internal::DiagnosticTypeForArg<Arg>::Conversion, arg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LocT, typename AnnotateFn>
|
||||
friend class DiagnosticAnnotationScope;
|
||||
|
||||
DiagnosticLocationTranslator<LocationT>* translator_;
|
||||
DiagnosticConverter<LocationT>* converter_;
|
||||
DiagnosticConsumer* consumer_;
|
||||
llvm::SmallVector<llvm::function_ref<auto(DiagnosticBuilder& builder)->void>>
|
||||
annotate_fns_;
|
||||
|
||||
@@ -15,17 +15,17 @@ namespace {
|
||||
|
||||
using ::Carbon::Testing::IsDiagnostic;
|
||||
|
||||
struct FakeDiagnosticLocationTranslator : DiagnosticLocationTranslator<int> {
|
||||
auto GetLocation(int n) -> DiagnosticLocation override {
|
||||
struct FakeDiagnosticConverter : DiagnosticConverter<int> {
|
||||
auto ConvertLocation(int n) const -> DiagnosticLocation override {
|
||||
return {.line_number = 1, .column_number = n};
|
||||
}
|
||||
};
|
||||
|
||||
class DiagnosticEmitterTest : public ::testing::Test {
|
||||
protected:
|
||||
DiagnosticEmitterTest() : emitter_(translator_, consumer_) {}
|
||||
DiagnosticEmitterTest() : emitter_(converter_, consumer_) {}
|
||||
|
||||
FakeDiagnosticLocationTranslator translator_;
|
||||
FakeDiagnosticConverter converter_;
|
||||
Testing::MockDiagnosticConsumer consumer_;
|
||||
DiagnosticEmitter<int> emitter_;
|
||||
};
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_TRANSLATOR_H_
|
||||
#define CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_TRANSLATOR_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "common/check.h"
|
||||
#include "llvm/ADT/Any.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
// Known diagnostic type translations. These are enumerated because `llvm::Any`
|
||||
// doesn't expose the contained type; instead, we infer it from a given
|
||||
// diagnostic.
|
||||
enum class DiagnosticTypeTranslation : int8_t {
|
||||
None,
|
||||
NameId,
|
||||
TypeId,
|
||||
};
|
||||
|
||||
// An interface that can translate some representation of a location into a
|
||||
// diagnostic location.
|
||||
//
|
||||
// TODO: Revisit this once the diagnostics machinery is more complete and see
|
||||
// if we can turn it into a `std::function`.
|
||||
template <typename LocationT>
|
||||
class DiagnosticLocationTranslator {
|
||||
public:
|
||||
virtual ~DiagnosticLocationTranslator() = default;
|
||||
|
||||
virtual auto GetLocation(LocationT loc) -> DiagnosticLocation = 0;
|
||||
|
||||
// Translates arg types as needed. Not all uses support translation, so the
|
||||
// default simply errors.
|
||||
virtual auto TranslateArg(DiagnosticTypeTranslation translation,
|
||||
llvm::Any /*arg*/) const -> llvm::Any {
|
||||
CARBON_FATAL() << "Unexpected call to TranslateArg: "
|
||||
<< static_cast<int8_t>(translation);
|
||||
}
|
||||
};
|
||||
|
||||
// Used by types to indicate a DiagnosticTypeTranslation that results in the
|
||||
// provided StorageType. For example, to translate NameId to a std::string, we
|
||||
// write:
|
||||
//
|
||||
// struct NameId {
|
||||
// using DiagnosticType =
|
||||
// DiagnosticTypeInfo<std::string, DiagnosticTypeTranslation::NameId>;
|
||||
// };
|
||||
template <typename StorageTypeT, DiagnosticTypeTranslation TranslationV>
|
||||
struct DiagnosticTypeInfo {
|
||||
using StorageType = StorageTypeT;
|
||||
static constexpr DiagnosticTypeTranslation Translation = TranslationV;
|
||||
};
|
||||
|
||||
namespace Internal {
|
||||
|
||||
// Determines whether there's a DiagnosticType member on Arg.
|
||||
// Used by DiagnosticEmitter.
|
||||
template <typename Arg>
|
||||
concept HasDiagnosticType =
|
||||
requires { std::type_identity<typename Arg::DiagnosticType>(); };
|
||||
|
||||
// The default implementation with no translation.
|
||||
template <typename Arg, typename /*Unused*/ = void>
|
||||
struct DiagnosticTypeForArg
|
||||
: public DiagnosticTypeInfo<Arg, DiagnosticTypeTranslation::None> {};
|
||||
|
||||
// Exposes a custom translation for an argument type.
|
||||
template <typename Arg>
|
||||
requires HasDiagnosticType<Arg>
|
||||
struct DiagnosticTypeForArg<Arg> : public Arg::DiagnosticType {};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_TRANSLATOR_H_
|
||||
@@ -10,15 +10,15 @@
|
||||
namespace Carbon {
|
||||
|
||||
template <typename LocationT>
|
||||
inline auto NullDiagnosticLocationTranslator()
|
||||
-> DiagnosticLocationTranslator<LocationT>& {
|
||||
struct Translator : DiagnosticLocationTranslator<LocationT> {
|
||||
auto GetLocation(LocationT /*loc*/) -> DiagnosticLocation override {
|
||||
inline auto NullDiagnosticConverter() -> DiagnosticConverter<LocationT>& {
|
||||
struct Converter : DiagnosticConverter<LocationT> {
|
||||
auto ConvertLocation(LocationT /*loc*/) const
|
||||
-> DiagnosticLocation override {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
static auto* translator = new Translator;
|
||||
return *translator;
|
||||
static auto* converter = new Converter;
|
||||
return *converter;
|
||||
}
|
||||
|
||||
inline auto NullDiagnosticConsumer() -> DiagnosticConsumer& {
|
||||
@@ -32,7 +32,7 @@ inline auto NullDiagnosticConsumer() -> DiagnosticConsumer& {
|
||||
template <typename LocationT>
|
||||
inline auto NullDiagnosticEmitter() -> DiagnosticEmitter<LocationT>& {
|
||||
static auto* emitter = new DiagnosticEmitter<LocationT>(
|
||||
NullDiagnosticLocationTranslator<LocationT>(), NullDiagnosticConsumer());
|
||||
NullDiagnosticConverter<LocationT>(), NullDiagnosticConsumer());
|
||||
return *emitter;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,18 +19,18 @@ using ::testing::InSequence;
|
||||
|
||||
CARBON_DIAGNOSTIC(TestDiagnostic, Error, "{0}", llvm::StringLiteral);
|
||||
|
||||
struct FakeDiagnosticLocationTranslator
|
||||
: DiagnosticLocationTranslator<DiagnosticLocation> {
|
||||
auto GetLocation(DiagnosticLocation loc) -> DiagnosticLocation override {
|
||||
struct FakeDiagnosticConverter : DiagnosticConverter<DiagnosticLocation> {
|
||||
auto ConvertLocation(DiagnosticLocation loc) const
|
||||
-> DiagnosticLocation override {
|
||||
return loc;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SortedDiagnosticEmitterTest, SortErrors) {
|
||||
FakeDiagnosticLocationTranslator translator;
|
||||
FakeDiagnosticConverter converter;
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
SortingDiagnosticConsumer sorting_consumer(consumer);
|
||||
DiagnosticEmitter<DiagnosticLocation> emitter(translator, sorting_consumer);
|
||||
DiagnosticEmitter<DiagnosticLocation> emitter(converter, sorting_consumer);
|
||||
|
||||
emitter.Emit({"f", "line", 2, 1}, TestDiagnostic, "M1");
|
||||
emitter.Emit({"f", "line", 1, 1}, TestDiagnostic, "M2");
|
||||
|
||||
@@ -77,10 +77,10 @@ class [[clang::internal_linkage]] Lexer {
|
||||
DiagnosticConsumer& consumer)
|
||||
: buffer_(value_stores, source),
|
||||
consumer_(consumer),
|
||||
translator_(&buffer_),
|
||||
emitter_(translator_, consumer_),
|
||||
token_translator_(&buffer_),
|
||||
token_emitter_(token_translator_, consumer_) {}
|
||||
converter_(&buffer_),
|
||||
emitter_(converter_, consumer_),
|
||||
token_converter_(&buffer_),
|
||||
token_emitter_(token_converter_, consumer_) {}
|
||||
|
||||
// Find all line endings and create the line data structures.
|
||||
//
|
||||
@@ -170,10 +170,10 @@ class [[clang::internal_linkage]] Lexer {
|
||||
|
||||
ErrorTrackingDiagnosticConsumer consumer_;
|
||||
|
||||
TokenizedBuffer::SourceBufferLocationTranslator translator_;
|
||||
TokenizedBuffer::SourceBufferDiagnosticConverter converter_;
|
||||
LexerDiagnosticEmitter emitter_;
|
||||
|
||||
TokenLocationTranslator token_translator_;
|
||||
TokenDiagnosticConverter token_converter_;
|
||||
TokenDiagnosticEmitter token_emitter_;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ class NumericLiteralTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
auto Parse(llvm::StringRef text) -> NumericLiteral::Value {
|
||||
Testing::SingleTokenDiagnosticTranslator translator(text);
|
||||
DiagnosticEmitter<const char*> emitter(translator, error_tracker);
|
||||
Testing::SingleTokenDiagnosticConverter converter(text);
|
||||
DiagnosticEmitter<const char*> emitter(converter, error_tracker);
|
||||
return Lex(text).ComputeValue(emitter);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ class StringLiteralTest : public ::testing::Test {
|
||||
|
||||
auto Parse(llvm::StringRef text) -> llvm::StringRef {
|
||||
StringLiteral token = Lex(text);
|
||||
Testing::SingleTokenDiagnosticTranslator translator(text);
|
||||
DiagnosticEmitter<const char*> emitter(translator, error_tracker);
|
||||
Testing::SingleTokenDiagnosticConverter converter(text);
|
||||
DiagnosticEmitter<const char*> emitter(converter, error_tracker);
|
||||
return token.ComputeValue(allocator, emitter);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,16 @@
|
||||
|
||||
namespace Carbon::Testing {
|
||||
|
||||
// A diagnostic translator for tests that lex a single token. Produces
|
||||
// A diagnostic converter for tests that lex a single token. Produces
|
||||
// locations such as "`12.5`:1:3" to refer to the third character in the token.
|
||||
class SingleTokenDiagnosticTranslator
|
||||
: public DiagnosticLocationTranslator<const char*> {
|
||||
class SingleTokenDiagnosticConverter : public DiagnosticConverter<const char*> {
|
||||
public:
|
||||
// Form a translator for a given token. The string provided here must refer
|
||||
// Form a converter for a given token. The string provided here must refer
|
||||
// to the same character array that we are going to lex.
|
||||
explicit SingleTokenDiagnosticTranslator(llvm::StringRef token)
|
||||
explicit SingleTokenDiagnosticConverter(llvm::StringRef token)
|
||||
: token_(token) {}
|
||||
|
||||
auto GetLocation(const char* pos) -> DiagnosticLocation override {
|
||||
auto ConvertLocation(const char* pos) const -> DiagnosticLocation override {
|
||||
CARBON_CHECK(StringRefContainsPointer(token_, pos))
|
||||
<< "invalid diagnostic location";
|
||||
llvm::StringRef prefix = token_.take_front(pos - token_.begin());
|
||||
|
||||
@@ -345,8 +345,8 @@ auto TokenIterator::Print(llvm::raw_ostream& output) const -> void {
|
||||
output << token_.index;
|
||||
}
|
||||
|
||||
auto TokenizedBuffer::SourceBufferLocationTranslator::GetLocation(
|
||||
const char* loc) -> DiagnosticLocation {
|
||||
auto TokenizedBuffer::SourceBufferDiagnosticConverter::ConvertLocation(
|
||||
const char* loc) const -> DiagnosticLocation {
|
||||
CARBON_CHECK(StringRefContainsPointer(buffer_->source_->text(), loc))
|
||||
<< "location not within buffer";
|
||||
int64_t offset = loc - buffer_->source_->text().begin();
|
||||
@@ -390,7 +390,7 @@ auto TokenizedBuffer::SourceBufferLocationTranslator::GetLocation(
|
||||
.column_number = column_number + 1};
|
||||
}
|
||||
|
||||
auto TokenLocationTranslator::GetLocation(TokenIndex token)
|
||||
auto TokenDiagnosticConverter::ConvertLocation(TokenIndex token) const
|
||||
-> DiagnosticLocation {
|
||||
// Map the token location into a position within the source buffer.
|
||||
const auto& token_info = buffer_->GetTokenInfo(token);
|
||||
@@ -402,7 +402,7 @@ auto TokenLocationTranslator::GetLocation(TokenIndex token)
|
||||
// TODO: Should we somehow indicate in the diagnostic location if this token
|
||||
// is a recovery token that doesn't correspond to the original source?
|
||||
DiagnosticLocation loc =
|
||||
TokenizedBuffer::SourceBufferLocationTranslator(buffer_).GetLocation(
|
||||
TokenizedBuffer::SourceBufferDiagnosticConverter(buffer_).ConvertLocation(
|
||||
token_start);
|
||||
loc.length = buffer_->GetTokenText(token).size();
|
||||
return loc;
|
||||
|
||||
@@ -111,16 +111,15 @@ class TokenIterator
|
||||
TokenIndex token_;
|
||||
};
|
||||
|
||||
// A diagnostic location translator that maps token locations into source
|
||||
// A diagnostic location converter that maps token locations into source
|
||||
// buffer locations.
|
||||
class TokenLocationTranslator
|
||||
: public DiagnosticLocationTranslator<TokenIndex> {
|
||||
class TokenDiagnosticConverter : public DiagnosticConverter<TokenIndex> {
|
||||
public:
|
||||
explicit TokenLocationTranslator(const TokenizedBuffer* buffer)
|
||||
explicit TokenDiagnosticConverter(const TokenizedBuffer* buffer)
|
||||
: buffer_(buffer) {}
|
||||
|
||||
// Map the given token into a diagnostic location.
|
||||
auto GetLocation(TokenIndex token) -> DiagnosticLocation override;
|
||||
auto ConvertLocation(TokenIndex token) const -> DiagnosticLocation override;
|
||||
|
||||
private:
|
||||
const TokenizedBuffer* buffer_;
|
||||
@@ -244,19 +243,19 @@ class TokenizedBuffer : public Printable<TokenizedBuffer> {
|
||||
|
||||
private:
|
||||
friend class Lexer;
|
||||
friend class TokenLocationTranslator;
|
||||
friend class TokenDiagnosticConverter;
|
||||
|
||||
// A diagnostic location translator that maps token locations into source
|
||||
// A diagnostic location converter that maps token locations into source
|
||||
// buffer locations.
|
||||
class SourceBufferLocationTranslator
|
||||
: public DiagnosticLocationTranslator<const char*> {
|
||||
class SourceBufferDiagnosticConverter
|
||||
: public DiagnosticConverter<const char*> {
|
||||
public:
|
||||
explicit SourceBufferLocationTranslator(const TokenizedBuffer* buffer)
|
||||
explicit SourceBufferDiagnosticConverter(const TokenizedBuffer* buffer)
|
||||
: buffer_(buffer) {}
|
||||
|
||||
// Map the given position within the source buffer into a diagnostic
|
||||
// location.
|
||||
auto GetLocation(const char* loc) -> DiagnosticLocation override;
|
||||
auto ConvertLocation(const char* loc) const -> DiagnosticLocation override;
|
||||
|
||||
private:
|
||||
const TokenizedBuffer* buffer_;
|
||||
|
||||
@@ -154,8 +154,8 @@ cc_fuzz_test(
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "tree_node_location_translator",
|
||||
hdrs = ["tree_node_location_translator.h"],
|
||||
name = "tree_node_diagnostic_converter",
|
||||
hdrs = ["tree_node_diagnostic_converter.h"],
|
||||
deps = [
|
||||
":tree",
|
||||
"//toolchain/diagnostics:diagnostic_emitter",
|
||||
|
||||
@@ -20,8 +20,8 @@ auto HandleInvalid(Context& context) -> void {
|
||||
|
||||
auto Parse(Lex::TokenizedBuffer& tokens, DiagnosticConsumer& consumer,
|
||||
llvm::raw_ostream* vlog_stream) -> Tree {
|
||||
Lex::TokenLocationTranslator translator(&tokens);
|
||||
Lex::TokenDiagnosticEmitter emitter(translator, consumer);
|
||||
Lex::TokenDiagnosticConverter converter(&tokens);
|
||||
Lex::TokenDiagnosticEmitter emitter(converter, consumer);
|
||||
|
||||
// Delegate to the parser.
|
||||
Tree tree(tokens);
|
||||
|
||||
+15
-14
@@ -2,8 +2,8 @@
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#ifndef CARBON_TOOLCHAIN_PARSE_TREE_NODE_LOCATION_TRANSLATOR_H_
|
||||
#define CARBON_TOOLCHAIN_PARSE_TREE_NODE_LOCATION_TRANSLATOR_H_
|
||||
#ifndef CARBON_TOOLCHAIN_PARSE_TREE_NODE_DIAGNOSTIC_CONVERTER_H_
|
||||
#define CARBON_TOOLCHAIN_PARSE_TREE_NODE_DIAGNOSTIC_CONVERTER_H_
|
||||
|
||||
#include "toolchain/diagnostics/diagnostic_emitter.h"
|
||||
#include "toolchain/lex/tokenized_buffer.h"
|
||||
@@ -34,18 +34,18 @@ inline auto TokenOnly(NodeId node_id) -> NodeLocation {
|
||||
return NodeLocation(node_id, true);
|
||||
}
|
||||
|
||||
class NodeLocationTranslator
|
||||
: public DiagnosticLocationTranslator<NodeLocation> {
|
||||
class NodeLocationConverter : public DiagnosticConverter<NodeLocation> {
|
||||
public:
|
||||
explicit NodeLocationTranslator(const Lex::TokenizedBuffer* tokens,
|
||||
llvm::StringRef filename,
|
||||
const Tree* parse_tree)
|
||||
: token_translator_(tokens),
|
||||
explicit NodeLocationConverter(const Lex::TokenizedBuffer* tokens,
|
||||
llvm::StringRef filename,
|
||||
const Tree* parse_tree)
|
||||
: token_converter_(tokens),
|
||||
filename_(filename),
|
||||
parse_tree_(parse_tree) {}
|
||||
|
||||
// Map the given token into a diagnostic location.
|
||||
auto GetLocation(NodeLocation node_location) -> DiagnosticLocation override {
|
||||
auto ConvertLocation(NodeLocation node_location) const
|
||||
-> DiagnosticLocation override {
|
||||
// Support the invalid token as a way to emit only the filename, when there
|
||||
// is no line association.
|
||||
if (!node_location.node_id().is_valid()) {
|
||||
@@ -53,7 +53,7 @@ class NodeLocationTranslator
|
||||
}
|
||||
|
||||
if (node_location.token_only()) {
|
||||
return token_translator_.GetLocation(
|
||||
return token_converter_.ConvertLocation(
|
||||
parse_tree_->node_token(node_location.node_id()));
|
||||
}
|
||||
|
||||
@@ -73,11 +73,12 @@ class NodeLocationTranslator
|
||||
end_token = desc_token;
|
||||
}
|
||||
}
|
||||
DiagnosticLocation start_loc = token_translator_.GetLocation(start_token);
|
||||
DiagnosticLocation start_loc =
|
||||
token_converter_.ConvertLocation(start_token);
|
||||
if (start_token == end_token) {
|
||||
return start_loc;
|
||||
}
|
||||
DiagnosticLocation end_loc = token_translator_.GetLocation(end_token);
|
||||
DiagnosticLocation end_loc = token_converter_.ConvertLocation(end_token);
|
||||
// For multiline locations we simply return the rest of the line for now
|
||||
// since true multiline locations are not yet supported.
|
||||
if (start_loc.line_number != end_loc.line_number) {
|
||||
@@ -92,11 +93,11 @@ class NodeLocationTranslator
|
||||
}
|
||||
|
||||
private:
|
||||
Lex::TokenLocationTranslator token_translator_;
|
||||
Lex::TokenDiagnosticConverter token_converter_;
|
||||
llvm::StringRef filename_;
|
||||
const Tree* parse_tree_;
|
||||
};
|
||||
|
||||
} // namespace Carbon::Parse
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_PARSE_TREE_NODE_LOCATION_TRANSLATOR_H_
|
||||
#endif // CARBON_TOOLCHAIN_PARSE_TREE_NODE_DIAGNOSTIC_CONVERTER_H_
|
||||
@@ -285,7 +285,7 @@ constexpr BoolValue BoolValue::True = BoolValue(1);
|
||||
struct NameId : public IdBase, public Printable<NameId> {
|
||||
// names().GetFormatted() is used for diagnostics.
|
||||
using DiagnosticType =
|
||||
DiagnosticTypeInfo<std::string, DiagnosticTypeTranslation::NameId>;
|
||||
DiagnosticTypeInfo<std::string, DiagnosticTypeConversion::NameId>;
|
||||
|
||||
// An explicitly invalid ID.
|
||||
static const NameId Invalid;
|
||||
@@ -423,7 +423,7 @@ struct TypeId : public IdBase, public Printable<TypeId> {
|
||||
using ValueType = TypeInfo;
|
||||
// StringifyType() is used for diagnostics.
|
||||
using DiagnosticType =
|
||||
DiagnosticTypeInfo<std::string, DiagnosticTypeTranslation::TypeId>;
|
||||
DiagnosticTypeInfo<std::string, DiagnosticTypeConversion::TypeId>;
|
||||
|
||||
// The builtin TypeType.
|
||||
static const TypeId TypeType;
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
namespace Carbon {
|
||||
|
||||
namespace {
|
||||
struct FilenameTranslator : DiagnosticLocationTranslator<llvm::StringRef> {
|
||||
auto GetLocation(llvm::StringRef filename) -> DiagnosticLocation override {
|
||||
struct FilenameConverter : DiagnosticConverter<llvm::StringRef> {
|
||||
auto ConvertLocation(llvm::StringRef filename) const
|
||||
-> DiagnosticLocation override {
|
||||
return {.filename = filename};
|
||||
}
|
||||
};
|
||||
@@ -28,8 +29,8 @@ auto SourceBuffer::MakeFromFile(llvm::vfs::FileSystem& fs,
|
||||
llvm::StringRef filename,
|
||||
DiagnosticConsumer& consumer)
|
||||
-> std::optional<SourceBuffer> {
|
||||
FilenameTranslator translator;
|
||||
DiagnosticEmitter<llvm::StringRef> emitter(translator, consumer);
|
||||
FilenameConverter converter;
|
||||
DiagnosticEmitter<llvm::StringRef> emitter(converter, consumer);
|
||||
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> file =
|
||||
fs.openFileForRead(filename);
|
||||
@@ -63,8 +64,8 @@ auto SourceBuffer::MakeFromMemoryBuffer(
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer,
|
||||
llvm::StringRef filename, bool is_regular_file,
|
||||
DiagnosticConsumer& consumer) -> std::optional<SourceBuffer> {
|
||||
FilenameTranslator translator;
|
||||
DiagnosticEmitter<llvm::StringRef> emitter(translator, consumer);
|
||||
FilenameConverter converter;
|
||||
DiagnosticEmitter<llvm::StringRef> emitter(converter, consumer);
|
||||
|
||||
if (buffer.getError()) {
|
||||
CARBON_DIAGNOSTIC(ErrorReadingFile, Error, "Error reading file: {0}",
|
||||
|
||||
Reference in New Issue
Block a user