mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:30:12 +01:00
Move diagnostics into a namespace (#5173)
What this really does is avoids shadowing names, so that we can comfortable have things like `Check::DiagnosticEmitter` or `Check::DiagnosticLoc` without shadowing being a concern. Note, down this path I'm also thinking about: - Renaming misc DiagnosticConsumer/DiagnosticEmitter classes, possibly just to DiagnosticConsumer/DiagnosticEmitter (so `Check::DiagnosticEmitter` instead of `SemIRLocDiagnosticEmitter`). - Dropping `Diagnostic` from `Emitter::DiagnosticBuilder`. - But not for `Check::DiagnosticBuilder`, because `Check::Builder` would be ambiguous. - Renaming diagnostics/diagnostic_* to drop "diagnostic". [Discussion about SemIRLoc -> DiagnosticLoc](https://discord.com/channels/655572317891461132/655578254970716160/1353771570463768698) reminded me of this (in particular the older [Check::DiagnosticBuilder discussion](https://discord.com/channels/655572317891461132/655578254970716160/1344363562608627763)), but I'd only do that rename if there's matching consensus about a path forward where we keep SemIRLoc, and in a way that it's only ever used for diagnostics (the divergence from which is at the root of current LocId discussion). I'm trying to keep that separate from a namespace addition for clarity.
This commit is contained in:
@@ -55,12 +55,13 @@ static auto ResolveCalleeInCall(Context& context, SemIR::LocId loc_id,
|
||||
"{0} argument{0:s} passed to "
|
||||
"{1:=0:function|=1:generic class|=2:generic interface}"
|
||||
" expecting {2} argument{2:s}",
|
||||
IntAsSelect, IntAsSelect, IntAsSelect);
|
||||
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect,
|
||||
Diagnostics::IntAsSelect);
|
||||
CARBON_DIAGNOSTIC(
|
||||
InCallToEntity, Note,
|
||||
"calling {0:=0:function|=1:generic class|=2:generic interface}"
|
||||
" declared here",
|
||||
IntAsSelect);
|
||||
Diagnostics::IntAsSelect);
|
||||
context.emitter()
|
||||
.Build(loc_id, CallArgCountMismatch, arg_ids.size(),
|
||||
static_cast<int>(entity_kind_for_diagnostic), params.size())
|
||||
@@ -218,7 +219,7 @@ auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id,
|
||||
SemIR::InstId return_slot_arg_id = SemIR::InstId::None;
|
||||
SemIR::ReturnTypeInfo return_info = [&] {
|
||||
auto& function = context.functions().Get(callee_function.function_id);
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(IncompleteReturnTypeHere, Note,
|
||||
"return type declared here");
|
||||
|
||||
@@ -302,7 +302,7 @@ static auto BuildApiMapAndDiagnosePackaging(
|
||||
CARBON_DIAGNOSTIC(
|
||||
IncorrectExtension, Error,
|
||||
"file extension of `{0:.impl|}.carbon` required for {0:`impl`|api}",
|
||||
BoolAsSelect);
|
||||
Diagnostics::BoolAsSelect);
|
||||
auto diag = unit_info.emitter.Build(
|
||||
packaging ? packaging->names.node_id : Parse::NodeId::None,
|
||||
IncorrectExtension, is_impl);
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Carbon::Check {
|
||||
|
||||
// Checking information that's tracked per file.
|
||||
struct Unit {
|
||||
DiagnosticConsumer* consumer;
|
||||
Diagnostics::Consumer* consumer;
|
||||
SharedValueStores* value_stores;
|
||||
// The `timings` may be null if nothing is to be recorded.
|
||||
Timings* timings;
|
||||
|
||||
@@ -50,16 +50,16 @@ struct PackageImports {
|
||||
// information), in addition to the `Unit` itself.
|
||||
struct UnitAndImports {
|
||||
// Converts a `NodeId` to a diagnostic location for `UnitAndImports`.
|
||||
class Emitter : public DiagnosticEmitter<Parse::NodeId> {
|
||||
class NodeEmitter : public Diagnostics::Emitter<Parse::NodeId> {
|
||||
public:
|
||||
explicit Emitter(DiagnosticConsumer* consumer,
|
||||
Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter)
|
||||
: DiagnosticEmitter(consumer),
|
||||
explicit NodeEmitter(Diagnostics::Consumer* consumer,
|
||||
Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter)
|
||||
: Emitter(consumer),
|
||||
tree_and_subtrees_getter_(tree_and_subtrees_getter) {}
|
||||
|
||||
protected:
|
||||
auto ConvertLoc(Parse::NodeId node_id, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> Diagnostics::ConvertedLoc override {
|
||||
return tree_and_subtrees_getter_().NodeToDiagnosticLoc(
|
||||
node_id, /*token_only=*/false);
|
||||
}
|
||||
@@ -83,8 +83,8 @@ struct UnitAndImports {
|
||||
Unit* unit;
|
||||
|
||||
// Emitter information.
|
||||
ErrorTrackingDiagnosticConsumer err_tracker;
|
||||
Emitter emitter;
|
||||
Diagnostics::ErrorTrackingConsumer err_tracker;
|
||||
NodeEmitter emitter;
|
||||
|
||||
// List of the outgoing imports. If a package includes unavailable library
|
||||
// imports, it has an entry with has_load_error set. Invalid imports (for
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
Context::Context(DiagnosticEmitter<SemIRLoc>* emitter,
|
||||
Context::Context(Diagnostics::Emitter<SemIRLoc>* emitter,
|
||||
Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter,
|
||||
SemIR::File* sem_ir, int imported_ir_count, int total_ir_count,
|
||||
llvm::raw_ostream* vlog_stream)
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Carbon::Check {
|
||||
class Context {
|
||||
public:
|
||||
// Stores references for work.
|
||||
explicit Context(DiagnosticEmitter<SemIRLoc>* emitter,
|
||||
explicit Context(Diagnostics::Emitter<SemIRLoc>* emitter,
|
||||
Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter,
|
||||
SemIR::File* sem_ir, int imported_ir_count,
|
||||
int total_ir_count, llvm::raw_ostream* vlog_stream);
|
||||
@@ -69,7 +69,7 @@ class Context {
|
||||
return tokens().GetKind(parse_tree().node_token(node_id));
|
||||
}
|
||||
|
||||
auto emitter() -> DiagnosticEmitter<SemIRLoc>& { return *emitter_; }
|
||||
auto emitter() -> Diagnostics::Emitter<SemIRLoc>& { return *emitter_; }
|
||||
|
||||
auto parse_tree_and_subtrees() -> const Parse::TreeAndSubtrees& {
|
||||
return tree_and_subtrees_getter_();
|
||||
@@ -276,7 +276,7 @@ class Context {
|
||||
|
||||
private:
|
||||
// Handles diagnostics.
|
||||
DiagnosticEmitter<SemIRLoc>* emitter_;
|
||||
Diagnostics::Emitter<SemIRLoc>* emitter_;
|
||||
|
||||
// Returns a lazily constructed TreeAndSubtrees.
|
||||
Parse::GetTreeAndSubtreesFn tree_and_subtrees_getter_;
|
||||
|
||||
@@ -270,12 +270,12 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type,
|
||||
CARBON_DIAGNOSTIC(ArrayInitFromLiteralArgCountMismatch, Error,
|
||||
"cannot initialize array of {0} element{0:s} from {1} "
|
||||
"initializer{1:s}",
|
||||
IntAsSelect, IntAsSelect);
|
||||
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect);
|
||||
CARBON_DIAGNOSTIC(
|
||||
ArrayInitFromExprArgCountMismatch, Error,
|
||||
"cannot initialize array of {0} element{0:s} from tuple "
|
||||
"with {1} element{1:s}",
|
||||
IntAsSelect, IntAsSelect);
|
||||
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect);
|
||||
context.emitter().Emit(value_loc_id,
|
||||
literal_elems.empty()
|
||||
? ArrayInitFromExprArgCountMismatch
|
||||
@@ -359,7 +359,7 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
|
||||
TupleInitElementCountMismatch, Error,
|
||||
"cannot initialize tuple of {0} element{0:s} from tuple "
|
||||
"with {1} element{1:s}",
|
||||
IntAsSelect, IntAsSelect);
|
||||
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect);
|
||||
context.emitter().Emit(value_loc_id, TupleInitElementCountMismatch,
|
||||
dest_elem_types.size(), src_elem_types.size());
|
||||
}
|
||||
@@ -459,7 +459,8 @@ static auto ConvertStructToStructOrClass(Context& context,
|
||||
StructInitElementCountMismatch, Error,
|
||||
"cannot initialize {0:class|struct} with {1} field{1:s} from struct "
|
||||
"with {2} field{2:s}",
|
||||
BoolAsSelect, IntAsSelect, IntAsSelect);
|
||||
Diagnostics::BoolAsSelect, Diagnostics::IntAsSelect,
|
||||
Diagnostics::IntAsSelect);
|
||||
context.emitter().Emit(value_loc_id, StructInitElementCountMismatch,
|
||||
ToClass, dest_elem_fields_size,
|
||||
src_elem_fields.size());
|
||||
@@ -869,7 +870,7 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
|
||||
// While the types are the same, the conversion can still fail if it
|
||||
// performs a copy while converting the value to another category, and
|
||||
// the type (or some part of it) is not copyable.
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(InCopy, Note, "in copy of {0}", TypeOfInstId);
|
||||
builder.Note(value_id, InCopy, value_id);
|
||||
@@ -1135,7 +1136,7 @@ static auto DiagnoseConversionFailureToConstraintValue(Context& context,
|
||||
ConversionFailureFacetToFacet, Error,
|
||||
"cannot{0:| implicitly} convert type {1} that implements {2} "
|
||||
"into type implementing {3}{0: with `as`|}",
|
||||
BoolAsSelect, InstIdAsType, TypeOfInstId, SemIR::TypeId);
|
||||
Diagnostics::BoolAsSelect, InstIdAsType, TypeOfInstId, SemIR::TypeId);
|
||||
return context.emitter().Build(
|
||||
loc_id, ConversionFailureFacetToFacet,
|
||||
target.kind == ConversionTarget::ExplicitAs, expr_id,
|
||||
@@ -1144,7 +1145,7 @@ static auto DiagnoseConversionFailureToConstraintValue(Context& context,
|
||||
CARBON_DIAGNOSTIC(ConversionFailureTypeToFacet, Error,
|
||||
"cannot{0:| implicitly} convert type {1} "
|
||||
"into type implementing {2}{0: with `as`|}",
|
||||
BoolAsSelect, InstIdAsType, SemIR::TypeId);
|
||||
Diagnostics::BoolAsSelect, InstIdAsType, SemIR::TypeId);
|
||||
return context.emitter().Build(
|
||||
loc_id, ConversionFailureTypeToFacet,
|
||||
target.kind == ConversionTarget::ExplicitAs, expr_id, target.type_id);
|
||||
@@ -1154,7 +1155,8 @@ static auto DiagnoseConversionFailureToConstraintValue(Context& context,
|
||||
ConversionFailureNonTypeToFacet, Error,
|
||||
"cannot{0:| implicitly} convert non-type value of type {1} "
|
||||
"{2:to|into type implementing} {3}{0: with `as`|}",
|
||||
BoolAsSelect, TypeOfInstId, BoolAsSelect, SemIR::TypeId);
|
||||
Diagnostics::BoolAsSelect, TypeOfInstId, Diagnostics::BoolAsSelect,
|
||||
SemIR::TypeId);
|
||||
return context.emitter().Build(
|
||||
loc_id, ConversionFailureNonTypeToFacet,
|
||||
target.kind == ConversionTarget::ExplicitAs, expr_id,
|
||||
@@ -1286,7 +1288,8 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
|
||||
CARBON_DIAGNOSTIC(ConversionFailure, Error,
|
||||
"cannot{0:| implicitly} convert value of type {1} to "
|
||||
"{2}{0: with `as`|}",
|
||||
BoolAsSelect, TypeOfInstId, SemIR::TypeId);
|
||||
Diagnostics::BoolAsSelect, TypeOfInstId,
|
||||
SemIR::TypeId);
|
||||
return context.emitter().Build(
|
||||
loc_id, ConversionFailure,
|
||||
target.kind == ConversionTarget::ExplicitAs, expr_id,
|
||||
|
||||
@@ -332,7 +332,7 @@ auto DeductionContext::Deduce() -> bool {
|
||||
// compile-time value (e.g. TupleType) that we can decompose further.
|
||||
// So we do this conversion here, even though we will later try convert
|
||||
// again when we have deduced all of the bindings.
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context().emitter(), [&](auto& builder) {
|
||||
if (diagnose_) {
|
||||
NoteInitializingParam(param_id, builder);
|
||||
@@ -573,7 +573,7 @@ auto DeductionContext::CheckDeductionIsComplete() -> bool {
|
||||
binding_type_id =
|
||||
context().types().GetTypeIdForTypeConstantId(param_type_const_id);
|
||||
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context().emitter(), [&](auto& builder) {
|
||||
if (diagnose_) {
|
||||
NoteInitializingParam(binding_id, builder);
|
||||
|
||||
@@ -46,7 +46,7 @@ class SemIRLoc {
|
||||
bool token_only_;
|
||||
};
|
||||
|
||||
using DiagnosticBuilder = DiagnosticEmitter<SemIRLoc>::DiagnosticBuilder;
|
||||
using DiagnosticBuilder = Diagnostics::Emitter<SemIRLoc>::DiagnosticBuilder;
|
||||
|
||||
// A function that forms a diagnostic for some kind of problem. The
|
||||
// DiagnosticBuilder is returned rather than emitted so that the caller
|
||||
@@ -69,7 +69,7 @@ inline auto TokenOnly(SemIR::LocId loc_id) -> SemIRLoc {
|
||||
// possible, because we should eventually be able to produce a sugared type name
|
||||
// in this case, whereas a `TypeId` will render as a canonical type.
|
||||
struct TypeOfInstId {
|
||||
using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
TypeOfInstId(SemIR::InstId inst_id) : inst_id(inst_id) {}
|
||||
@@ -86,7 +86,7 @@ struct TypeOfInstId {
|
||||
// This should be used when the source expression used to construct a type is
|
||||
// available.
|
||||
struct InstIdAsType {
|
||||
using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
InstIdAsType(SemIR::InstId inst_id) : inst_id(inst_id) {}
|
||||
@@ -103,7 +103,7 @@ struct InstIdAsType {
|
||||
// This is intended for cases where the type is part of a larger syntactic
|
||||
// construct in a diagnostic, such as "redefinition of `impl {0} as {1}`".
|
||||
struct InstIdAsRawType {
|
||||
using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
InstIdAsRawType(SemIR::InstId inst_id) : inst_id(inst_id) {}
|
||||
@@ -118,7 +118,7 @@ struct InstIdAsRawType {
|
||||
// possible, because it can't be formatted with syntactic sugar such as aliases
|
||||
// that describe how the type was written.
|
||||
struct TypeIdAsRawType {
|
||||
using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
TypeIdAsRawType(SemIR::TypeId type_id) : type_id(type_id) {}
|
||||
@@ -129,7 +129,7 @@ struct TypeIdAsRawType {
|
||||
// An integer value together with its type. The type is used to determine how to
|
||||
// format the value in diagnostics.
|
||||
struct TypedInt {
|
||||
using DiagnosticType = DiagnosticTypeInfo<llvm::APSInt>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<llvm::APSInt>;
|
||||
|
||||
SemIR::TypeId type;
|
||||
llvm::APInt value;
|
||||
|
||||
@@ -187,7 +187,9 @@ class EvalContext {
|
||||
|
||||
auto sem_ir() -> SemIR::File& { return context().sem_ir(); }
|
||||
|
||||
auto emitter() -> DiagnosticEmitter<SemIRLoc>& { return context().emitter(); }
|
||||
auto emitter() -> Diagnostics::Emitter<SemIRLoc>& {
|
||||
return context().emitter();
|
||||
}
|
||||
|
||||
private:
|
||||
// The type-checking context in which we're performing evaluation.
|
||||
@@ -1036,7 +1038,7 @@ static auto PerformBuiltinIntShiftOp(Context& context, SemIRLoc loc,
|
||||
CARBON_DIAGNOSTIC(
|
||||
CompileTimeShiftOutOfRange, Error,
|
||||
"shift distance >= type width of {0} in `{1} {2:<<|>>} {3}`", unsigned,
|
||||
TypedInt, BoolAsSelect, TypedInt);
|
||||
TypedInt, Diagnostics::BoolAsSelect, TypedInt);
|
||||
context.emitter().Emit(
|
||||
loc, CompileTimeShiftOutOfRange, lhs_val.getBitWidth(),
|
||||
{.type = lhs.type_id, .value = lhs_val},
|
||||
@@ -1050,7 +1052,7 @@ static auto PerformBuiltinIntShiftOp(Context& context, SemIRLoc loc,
|
||||
context.sem_ir().types().IsSignedInt(rhs.type_id)) {
|
||||
CARBON_DIAGNOSTIC(CompileTimeShiftNegative, Error,
|
||||
"shift distance negative in `{0} {1:<<|>>} {2}`",
|
||||
TypedInt, BoolAsSelect, TypedInt);
|
||||
TypedInt, Diagnostics::BoolAsSelect, TypedInt);
|
||||
context.emitter().Emit(
|
||||
loc, CompileTimeShiftNegative, {.type = lhs.type_id, .value = lhs_val},
|
||||
builtin_kind == SemIR::BuiltinFunctionKind::IntLeftShift,
|
||||
@@ -1888,7 +1890,7 @@ auto TryEvalBlockForSpecific(Context& context, SemIRLoc loc,
|
||||
.values = result,
|
||||
});
|
||||
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(ResolvingSpecificHere, Note, "in {0} used here",
|
||||
InstIdAsType);
|
||||
|
||||
@@ -111,7 +111,7 @@ static auto HandleIntOrUnsignedIntTypeLiteral(Context& context,
|
||||
CARBON_DIAGNOSTIC(IntWidthNotMultipleOf8, Error,
|
||||
"bit width of integer type literal must be a multiple of "
|
||||
"8; use `Core.{0:Int|UInt}({1})` instead",
|
||||
BoolAsSelect, llvm::APSInt);
|
||||
Diagnostics::BoolAsSelect, llvm::APSInt);
|
||||
context.emitter().Emit(
|
||||
node_id, IntWidthNotMultipleOf8, int_kind.is_signed(),
|
||||
llvm::APSInt(context.ints().Get(size_id), /*isUnsigned=*/true));
|
||||
|
||||
@@ -266,7 +266,7 @@ auto HandleParseNode(Context& context, Parse::DesignatorExprId node_id)
|
||||
// instead so we can generate a "name `.Self` implicitly referenced by
|
||||
// designated expression, but not found" diagnostic instead of adding a
|
||||
// note to the current "name `.Self` not found" message.
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
NoPeriodSelfForDesignator, Note,
|
||||
|
||||
@@ -87,7 +87,7 @@ static auto DiagnoseDuplicateNames(
|
||||
CARBON_DIAGNOSTIC(StructNameDuplicate, Error,
|
||||
"duplicated field name `{1}` in "
|
||||
"{0:struct type literal|struct literal}",
|
||||
BoolAsSelect, SemIR::NameId);
|
||||
Diagnostics::BoolAsSelect, SemIR::NameId);
|
||||
CARBON_DIAGNOSTIC(StructNamePrevious, Note,
|
||||
"field with the same name here");
|
||||
context.emitter()
|
||||
|
||||
@@ -617,7 +617,7 @@ auto ImportNameFromOtherPackage(
|
||||
}
|
||||
|
||||
// Annotate diagnostics as occurring during this name lookup.
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(InNameLookup, Note, "in name lookup for `{0}`",
|
||||
SemIR::NameId);
|
||||
|
||||
@@ -83,13 +83,15 @@ static auto GenerateAst(Context& context, llvm::StringRef importing_file_path,
|
||||
CARBON_DIAGNOSTIC(
|
||||
CppInteropParseError, Error,
|
||||
"{0} error{0:s} and {1} warning{1:s} in {2} `Cpp` import{2:s}:\n{3}",
|
||||
IntAsSelect, IntAsSelect, IntAsSelect, std::string);
|
||||
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect,
|
||||
Diagnostics::IntAsSelect, std::string);
|
||||
context.emitter().Emit(loc, CppInteropParseError, num_errors, num_warnings,
|
||||
num_imports, diagnostics_str);
|
||||
} else if (num_warnings > 0) {
|
||||
CARBON_DIAGNOSTIC(CppInteropParseWarning, Warning,
|
||||
"{0} warning{0:s} in `Cpp` {1} import{1:s}:\n{2}",
|
||||
IntAsSelect, IntAsSelect, std::string);
|
||||
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect,
|
||||
std::string);
|
||||
context.emitter().Emit(loc, CppInteropParseWarning, num_warnings,
|
||||
num_imports, diagnostics_str);
|
||||
}
|
||||
@@ -348,7 +350,7 @@ static auto ImportNameDecl(Context& context, SemIR::LocId loc_id,
|
||||
auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::NameScopeId scope_id, SemIR::NameId name_id)
|
||||
-> SemIR::InstId {
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(InCppNameLookup, Note,
|
||||
"in `Cpp` name lookup for `{0}`", SemIR::NameId);
|
||||
|
||||
@@ -209,14 +209,14 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
|
||||
CARBON_DIAGNOSTIC(
|
||||
RedeclParamPrevious, Note,
|
||||
"previous declaration's corresponding {0:implicit |}parameter here",
|
||||
BoolAsSelect);
|
||||
Diagnostics::BoolAsSelect);
|
||||
auto emit_diagnostic = [&]() {
|
||||
if (!diagnose) {
|
||||
return;
|
||||
}
|
||||
CARBON_DIAGNOSTIC(RedeclParamDiffers, Error,
|
||||
"redeclaration differs at {0:implicit |}parameter {1}",
|
||||
BoolAsSelect, int32_t);
|
||||
Diagnostics::BoolAsSelect, int32_t);
|
||||
context.emitter()
|
||||
.Build(new_param_pattern_id, RedeclParamDiffers, is_implicit_param,
|
||||
param_index + 1)
|
||||
@@ -277,7 +277,8 @@ static auto CheckRedeclParam(Context& context, bool is_implicit_param,
|
||||
CARBON_DIAGNOSTIC(RedeclParamDiffersType, Error,
|
||||
"type {3} of {0:implicit |}parameter {1} in "
|
||||
"redeclaration differs from previous parameter type {2}",
|
||||
BoolAsSelect, int32_t, SemIR::TypeId, SemIR::TypeId);
|
||||
Diagnostics::BoolAsSelect, int32_t, SemIR::TypeId,
|
||||
SemIR::TypeId);
|
||||
context.emitter()
|
||||
.Build(new_param_pattern_id, RedeclParamDiffersType, is_implicit_param,
|
||||
param_index + 1, prev_param_type_id, new_param_pattern.type_id())
|
||||
@@ -315,11 +316,11 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
|
||||
CARBON_DIAGNOSTIC(RedeclParamListDiffers, Error,
|
||||
"redeclaration differs because of "
|
||||
"{1:|missing }{0:implicit |}parameter list",
|
||||
BoolAsSelect, BoolAsSelect);
|
||||
Diagnostics::BoolAsSelect, Diagnostics::BoolAsSelect);
|
||||
CARBON_DIAGNOSTIC(RedeclParamListPrevious, Note,
|
||||
"previously declared "
|
||||
"{1:with|without} {0:implicit |}parameter list",
|
||||
BoolAsSelect, BoolAsSelect);
|
||||
Diagnostics::BoolAsSelect, Diagnostics::BoolAsSelect);
|
||||
context.emitter()
|
||||
.Build(new_decl_loc, RedeclParamListDiffers, is_implicit_param,
|
||||
new_param_patterns_id.has_value())
|
||||
@@ -342,11 +343,11 @@ static auto CheckRedeclParams(Context& context, SemIRLoc new_decl_loc,
|
||||
CARBON_DIAGNOSTIC(
|
||||
RedeclParamCountDiffers, Error,
|
||||
"redeclaration differs because of {0:implicit |}parameter count of {1}",
|
||||
BoolAsSelect, int32_t);
|
||||
Diagnostics::BoolAsSelect, int32_t);
|
||||
CARBON_DIAGNOSTIC(
|
||||
RedeclParamCountPrevious, Note,
|
||||
"previously declared with {0:implicit |}parameter count of {1}",
|
||||
BoolAsSelect, int32_t);
|
||||
Diagnostics::BoolAsSelect, int32_t);
|
||||
context.emitter()
|
||||
.Build(new_decl_loc, RedeclParamCountDiffers, is_implicit_param,
|
||||
new_param_pattern_ids.size())
|
||||
|
||||
@@ -11,9 +11,10 @@ namespace Carbon::Check {
|
||||
// Builds the diagnostic for DiagnoseNotAllowed.
|
||||
template <typename... TokenKinds>
|
||||
static auto StartDiagnoseNotAllowed(
|
||||
Context& context, const DiagnosticBase<TokenKinds...>& diagnostic_base,
|
||||
Context& context,
|
||||
const Diagnostics::DiagnosticBase<TokenKinds...>& diagnostic_base,
|
||||
Parse::NodeId modifier_node, Lex::TokenKind declaration_kind)
|
||||
-> DiagnosticEmitter<SemIRLoc>::DiagnosticBuilder {
|
||||
-> Diagnostics::Emitter<SemIRLoc>::DiagnosticBuilder {
|
||||
if constexpr (sizeof...(TokenKinds) == 0) {
|
||||
return context.emitter().Build(modifier_node, diagnostic_base);
|
||||
} else if constexpr (sizeof...(TokenKinds) == 1) {
|
||||
@@ -34,7 +35,8 @@ static auto StartDiagnoseNotAllowed(
|
||||
// declaration kind.
|
||||
template <typename... TokenKinds>
|
||||
static auto DiagnoseNotAllowed(
|
||||
Context& context, const DiagnosticBase<TokenKinds...>& diagnostic_base,
|
||||
Context& context,
|
||||
const Diagnostics::DiagnosticBase<TokenKinds...>& diagnostic_base,
|
||||
Parse::NodeId modifier_node, Lex::TokenKind decl_kind,
|
||||
SemIR::LocId context_loc_id) -> void {
|
||||
auto diag = StartDiagnoseNotAllowed(context, diagnostic_base, modifier_node,
|
||||
|
||||
@@ -225,7 +225,7 @@ static auto DiagnoseInvalidQualifiedNameAccess(Context& context, SemIRLoc loc,
|
||||
CARBON_DIAGNOSTIC(
|
||||
ClassInvalidMemberAccess, Error,
|
||||
"cannot access {0:private|protected} member `{1}` of type {2}",
|
||||
BoolAsSelect, SemIR::NameId, SemIR::TypeId);
|
||||
Diagnostics::BoolAsSelect, SemIR::NameId, SemIR::TypeId);
|
||||
CARBON_DIAGNOSTIC(ClassMemberDeclaration, Note, "declared here");
|
||||
context.emitter()
|
||||
.Build(loc, ClassInvalidMemberAccess,
|
||||
@@ -424,7 +424,7 @@ auto LookupQualifiedName(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ConstantId const_id = GetConstantValueInSpecific(
|
||||
context.sem_ir(), specific_id, extended_id);
|
||||
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(FromExtendHere, Note,
|
||||
"declared as an extended scope here");
|
||||
|
||||
@@ -493,7 +493,7 @@ auto MatchContext::DoEmitPatternMatch(Context& context,
|
||||
CARBON_DIAGNOSTIC(TuplePatternSizeDoesntMatchLiteral, Error,
|
||||
"tuple pattern expects {0} element{0:s}, but tuple "
|
||||
"literal has {1}",
|
||||
IntAsSelect, IntAsSelect);
|
||||
Diagnostics::IntAsSelect, Diagnostics::IntAsSelect);
|
||||
context.emitter().Emit(pattern_loc_id, TuplePatternSizeDoesntMatchLiteral,
|
||||
subpattern_ids.size(), subscrutinee_ids.size());
|
||||
return;
|
||||
@@ -531,7 +531,7 @@ auto MatchContext::EmitPatternMatch(Context& context,
|
||||
if (entry.pattern_id == SemIR::ErrorInst::SingletonInstId) {
|
||||
return;
|
||||
}
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
if (kind_ == MatchKind::Caller) {
|
||||
CARBON_DIAGNOSTIC(InCallToFunctionParam, Note,
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Carbon::Check {
|
||||
|
||||
auto SemIRLocDiagnosticEmitter::ConvertLoc(SemIRLoc loc,
|
||||
ContextFnT context_fn) const
|
||||
-> ConvertedDiagnosticLoc {
|
||||
-> Diagnostics::ConvertedLoc {
|
||||
auto converted = ConvertLocImpl(loc, context_fn);
|
||||
|
||||
// Use the token when possible, but -1 is the default value.
|
||||
@@ -35,7 +35,7 @@ auto SemIRLocDiagnosticEmitter::ConvertLoc(SemIRLoc loc,
|
||||
|
||||
auto SemIRLocDiagnosticEmitter::ConvertLocImpl(SemIRLoc loc,
|
||||
ContextFnT context_fn) const
|
||||
-> ConvertedDiagnosticLoc {
|
||||
-> Diagnostics::ConvertedLoc {
|
||||
llvm::SmallVector<SemIR::AbsoluteNodeId> absolute_node_ids =
|
||||
loc.is_inst_id_ ? SemIR::GetAbsoluteNodeId(sem_ir_, loc.inst_id_)
|
||||
: SemIR::GetAbsoluteNodeId(sem_ir_, loc.loc_id_);
|
||||
@@ -59,7 +59,7 @@ auto SemIRLocDiagnosticEmitter::ConvertLocImpl(SemIRLoc loc,
|
||||
|
||||
auto SemIRLocDiagnosticEmitter::ConvertLocInFile(
|
||||
SemIR::AbsoluteNodeId absolute_node_id, bool token_only,
|
||||
ContextFnT /*context_fn*/) const -> ConvertedDiagnosticLoc {
|
||||
ContextFnT /*context_fn*/) const -> Diagnostics::ConvertedLoc {
|
||||
const auto& tree_and_subtrees =
|
||||
tree_and_subtrees_getters_[absolute_node_id.check_ir_id.index]();
|
||||
return tree_and_subtrees.NodeToDiagnosticLoc(absolute_node_id.node_id,
|
||||
@@ -118,7 +118,7 @@ auto SemIRLocDiagnosticEmitter::ConvertArg(llvm::Any arg) const -> llvm::Any {
|
||||
return llvm::APSInt(typed_int->value,
|
||||
!sem_ir_->types().IsSignedInt(typed_int->type));
|
||||
}
|
||||
return DiagnosticEmitter<SemIRLoc>::ConvertArg(arg);
|
||||
return Diagnostics::Emitter<SemIRLoc>::ConvertArg(arg);
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
namespace Carbon::Check {
|
||||
|
||||
// Handles the transformation of a SemIRLoc to a DiagnosticLoc.
|
||||
class SemIRLocDiagnosticEmitter : public DiagnosticEmitter<SemIRLoc> {
|
||||
class SemIRLocDiagnosticEmitter : public Diagnostics::Emitter<SemIRLoc> {
|
||||
public:
|
||||
explicit SemIRLocDiagnosticEmitter(
|
||||
DiagnosticConsumer* consumer,
|
||||
Diagnostics::Consumer* consumer,
|
||||
llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> tree_and_subtrees_getters,
|
||||
const SemIR::File* sem_ir)
|
||||
: DiagnosticEmitter(consumer),
|
||||
: Emitter(consumer),
|
||||
tree_and_subtrees_getters_(tree_and_subtrees_getters),
|
||||
sem_ir_(sem_ir) {}
|
||||
|
||||
@@ -44,17 +44,18 @@ class SemIRLocDiagnosticEmitter : public DiagnosticEmitter<SemIRLoc> {
|
||||
// locations, or `loc` if it's in the same file and (for whatever reason)
|
||||
// later.
|
||||
auto ConvertLoc(SemIRLoc loc, ContextFnT context_fn) const
|
||||
-> ConvertedDiagnosticLoc override;
|
||||
-> Diagnostics::ConvertedLoc override;
|
||||
|
||||
private:
|
||||
// Implements `ConvertLoc`, but without `last_token_` applied.
|
||||
auto ConvertLocImpl(SemIRLoc loc, ContextFnT context_fn) const
|
||||
-> ConvertedDiagnosticLoc;
|
||||
-> Diagnostics::ConvertedLoc;
|
||||
|
||||
// Converts a node_id corresponding to a specific sem_ir to a diagnostic
|
||||
// location.
|
||||
auto ConvertLocInFile(SemIR::AbsoluteNodeId absolute_node_id, bool token_only,
|
||||
ContextFnT context_fn) const -> ConvertedDiagnosticLoc;
|
||||
ContextFnT context_fn) const
|
||||
-> Diagnostics::ConvertedLoc;
|
||||
|
||||
// Converters for each SemIR.
|
||||
llvm::ArrayRef<Parse::GetTreeAndSubtreesFn> tree_and_subtrees_getters_;
|
||||
|
||||
@@ -579,7 +579,7 @@ static auto NoteAbstractClass(Context& context, SemIR::ClassId class_id,
|
||||
CARBON_DIAGNOSTIC(
|
||||
ClassAbstractHere, Note,
|
||||
"{0:=0:uses class that|=1:class} was declared abstract here",
|
||||
IntAsSelect);
|
||||
Diagnostics::IntAsSelect);
|
||||
builder.Note(class_info.definition_id, ClassAbstractHere,
|
||||
static_cast<int>(direct_use));
|
||||
}
|
||||
|
||||
@@ -11,37 +11,37 @@
|
||||
ABSL_FLAG(std::string, testdata_manifest, "",
|
||||
"A path to a file containing repo-relative names of test files.");
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
namespace {
|
||||
|
||||
constexpr DiagnosticKind DiagnosticKinds[] = {
|
||||
#define CARBON_DIAGNOSTIC_KIND(Name) DiagnosticKind::Name,
|
||||
constexpr Kind Kinds[] = {
|
||||
#define CARBON_DIAGNOSTIC_KIND(Name) Kind::Name,
|
||||
#include "toolchain/diagnostics/diagnostic_kind.def"
|
||||
};
|
||||
|
||||
constexpr DiagnosticKind UntestedDiagnosticKinds[] = {
|
||||
constexpr Kind UntestedKinds[] = {
|
||||
// These exist only for unit tests.
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticKind::TestDiagnosticNote,
|
||||
Kind::TestDiagnostic,
|
||||
Kind::TestDiagnosticNote,
|
||||
|
||||
// Diagnosing erroneous install conditions, but test environments are
|
||||
// typically correct.
|
||||
DiagnosticKind::CompilePreludeManifestError,
|
||||
DiagnosticKind::DriverInstallInvalid,
|
||||
Kind::CompilePreludeManifestError,
|
||||
Kind::DriverInstallInvalid,
|
||||
|
||||
// These diagnose filesystem issues that are hard to unit test.
|
||||
DiagnosticKind::ErrorReadingFile,
|
||||
DiagnosticKind::ErrorStattingFile,
|
||||
DiagnosticKind::FileTooLarge,
|
||||
Kind::ErrorReadingFile,
|
||||
Kind::ErrorStattingFile,
|
||||
Kind::FileTooLarge,
|
||||
|
||||
// These aren't feasible to test with a normal testcase, but are tested in
|
||||
// lex/tokenized_buffer_test.cpp.
|
||||
DiagnosticKind::TooManyTokens,
|
||||
DiagnosticKind::UnsupportedCrLineEnding,
|
||||
DiagnosticKind::UnsupportedLfCrLineEnding,
|
||||
Kind::TooManyTokens,
|
||||
Kind::UnsupportedCrLineEnding,
|
||||
Kind::UnsupportedLfCrLineEnding,
|
||||
|
||||
// This is a little long but is tested in lex/numeric_literal_test.cpp.
|
||||
DiagnosticKind::TooManyDigits,
|
||||
Kind::TooManyDigits,
|
||||
|
||||
// TODO: This can only fire if the first message in a diagnostic is rooted
|
||||
// in a file other than the file being compiled. The language server
|
||||
@@ -50,16 +50,16 @@ constexpr DiagnosticKind UntestedDiagnosticKinds[] = {
|
||||
// in the current file.
|
||||
// - Require all diagnostics produced by compiling have their first location
|
||||
// be in the file being compiled, never an import.
|
||||
DiagnosticKind::LanguageServerDiagnosticInWrongFile,
|
||||
Kind::LanguageServerDiagnosticInWrongFile,
|
||||
};
|
||||
|
||||
// Looks for diagnostic kinds that aren't covered by a file_test.
|
||||
TEST(Coverage, DiagnosticKind) {
|
||||
TEST(Coverage, Kind) {
|
||||
Testing::TestKindCoverage(absl::GetFlag(FLAGS_testdata_manifest),
|
||||
R"(^ *// CHECK:STDERR: .* \[(\w+)\]$)",
|
||||
llvm::ArrayRef(DiagnosticKinds),
|
||||
llvm::ArrayRef(UntestedDiagnosticKinds));
|
||||
llvm::ArrayRef(Kinds),
|
||||
llvm::ArrayRef(UntestedKinds));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
auto DiagnosticLoc::FormatLocation(llvm::raw_ostream& out) const -> void {
|
||||
auto Loc::FormatLocation(llvm::raw_ostream& out) const -> void {
|
||||
if (filename.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -23,8 +23,7 @@ auto DiagnosticLoc::FormatLocation(llvm::raw_ostream& out) const -> void {
|
||||
out << ": ";
|
||||
}
|
||||
|
||||
auto DiagnosticLoc::FormatSnippet(llvm::raw_ostream& out, int indent) const
|
||||
-> void {
|
||||
auto Loc::FormatSnippet(llvm::raw_ostream& out, int indent) const -> void {
|
||||
if (column_number == -1) {
|
||||
return;
|
||||
}
|
||||
@@ -48,4 +47,4 @@ auto DiagnosticLoc::FormatSnippet(llvm::raw_ostream& out, int indent) const
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "toolchain/diagnostics/diagnostic_kind.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
enum class DiagnosticLevel : int8_t {
|
||||
enum class Level : int8_t {
|
||||
// Information about the location of another diagnostic, showing how we
|
||||
// reached that location. This is currently only used for the "in import"
|
||||
// message.
|
||||
@@ -39,17 +39,17 @@ enum class DiagnosticLevel : int8_t {
|
||||
// Arguments are passed to llvm::formatv; see:
|
||||
// https://llvm.org/doxygen/FormatVariadic_8h_source.html
|
||||
//
|
||||
// See `DiagnosticEmitter::Emit` for comments about argument lifetimes.
|
||||
#define CARBON_DIAGNOSTIC(DiagnosticName, Level, Format, ...) \
|
||||
static constexpr auto DiagnosticName = \
|
||||
::Carbon::DiagnosticBase<__VA_ARGS__>( \
|
||||
::Carbon::DiagnosticKind::DiagnosticName, \
|
||||
::Carbon::DiagnosticLevel::Level, Format)
|
||||
// See `Diagnostics::Emitter::Emit` for comments about argument lifetimes.
|
||||
#define CARBON_DIAGNOSTIC(DiagnosticName, LevelValue, Format, ...) \
|
||||
static constexpr auto DiagnosticName = \
|
||||
::Carbon::Diagnostics::DiagnosticBase<__VA_ARGS__>( \
|
||||
::Carbon::Diagnostics::Kind::DiagnosticName, \
|
||||
::Carbon::Diagnostics::Level::LevelValue, Format)
|
||||
|
||||
// A location for a diagnostic in a file. The lifetime of a DiagnosticLoc
|
||||
// A location for a diagnostic in a file. The lifetime of a Loc
|
||||
// is required to be less than SourceBuffer that it refers to due to the
|
||||
// contained filename and line references.
|
||||
struct DiagnosticLoc {
|
||||
struct Loc {
|
||||
// Writes the location to the given stream. It will be formatted as
|
||||
// `<filename>:<line_number>:<column_number>: ` with parts dropped when
|
||||
// unknown.
|
||||
@@ -78,18 +78,18 @@ struct DiagnosticLoc {
|
||||
|
||||
// A message composing a diagnostic. This may be the main message, but can also
|
||||
// be notes providing more information.
|
||||
struct DiagnosticMessage {
|
||||
struct Message {
|
||||
// Helper for calling `format_fn`.
|
||||
auto Format() const -> std::string { return format_fn(*this); }
|
||||
|
||||
// The diagnostic's kind.
|
||||
DiagnosticKind kind;
|
||||
Kind kind;
|
||||
|
||||
// The diagnostic's level.
|
||||
DiagnosticLevel level;
|
||||
Level level;
|
||||
|
||||
// The calculated location of the diagnostic.
|
||||
DiagnosticLoc loc;
|
||||
Loc loc;
|
||||
|
||||
// The diagnostic's format string. This, along with format_args, will be
|
||||
// passed to format_fn.
|
||||
@@ -104,18 +104,18 @@ struct DiagnosticMessage {
|
||||
llvm::SmallVector<llvm::Any> format_args;
|
||||
|
||||
// Returns the formatted string. By default, this uses llvm::formatv.
|
||||
std::function<auto(const DiagnosticMessage&)->std::string> format_fn;
|
||||
std::function<auto(const Message&)->std::string> format_fn;
|
||||
};
|
||||
|
||||
// An instance of a single error or warning. Information about the diagnostic
|
||||
// can be recorded into it for more complex consumers.
|
||||
struct Diagnostic {
|
||||
// The diagnostic's level.
|
||||
DiagnosticLevel level;
|
||||
Level level;
|
||||
|
||||
// The byte offset of the final token which is associated with the diagnostic.
|
||||
// This is used by `SortingDiagnosticConsumer`. This is separate from the
|
||||
// `DiagnosticLoc` because it must refer to a position in the primary file
|
||||
// This is used by `SortingConsumer`. This is separate from the
|
||||
// `Loc` because it must refer to a position in the primary file
|
||||
// being processed by a consumer, and has no use cross-file or in notes.
|
||||
//
|
||||
// This will usually be the start position (not end) of the last lexed token
|
||||
@@ -127,14 +127,14 @@ struct Diagnostic {
|
||||
|
||||
// Messages related to the diagnostic. Only one should be a warning or error;
|
||||
// other messages provide context.
|
||||
llvm::SmallVector<DiagnosticMessage> messages;
|
||||
llvm::SmallVector<Message> messages;
|
||||
};
|
||||
|
||||
// Use the DIAGNOSTIC macro to instantiate this.
|
||||
// This stores static information about a diagnostic category.
|
||||
template <typename... Args>
|
||||
struct DiagnosticBase {
|
||||
explicit constexpr DiagnosticBase(DiagnosticKind kind, DiagnosticLevel level,
|
||||
explicit constexpr DiagnosticBase(Kind kind, Level level,
|
||||
llvm::StringLiteral format)
|
||||
: Kind(kind), Level(level), Format(format) {
|
||||
static_assert((... && !(std::is_same_v<Args, llvm::StringRef> ||
|
||||
@@ -145,13 +145,13 @@ struct DiagnosticBase {
|
||||
}
|
||||
|
||||
// The diagnostic's kind.
|
||||
DiagnosticKind Kind;
|
||||
Kind Kind;
|
||||
// The diagnostic's level.
|
||||
DiagnosticLevel Level;
|
||||
Level Level;
|
||||
// The diagnostic's format for llvm::formatv.
|
||||
llvm::StringLiteral Format;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_H_
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
auto StreamDiagnosticConsumer::HandleDiagnostic(Diagnostic diagnostic) -> void {
|
||||
auto StreamConsumer::HandleDiagnostic(Diagnostic diagnostic) -> void {
|
||||
if (printed_diagnostic_) {
|
||||
*stream_ << "\n";
|
||||
} else {
|
||||
@@ -19,16 +19,16 @@ auto StreamDiagnosticConsumer::HandleDiagnostic(Diagnostic diagnostic) -> void {
|
||||
for (const auto& message : diagnostic.messages) {
|
||||
message.loc.FormatLocation(*stream_);
|
||||
switch (message.level) {
|
||||
case DiagnosticLevel::Error:
|
||||
case Level::Error:
|
||||
*stream_ << "error: ";
|
||||
break;
|
||||
case DiagnosticLevel::Warning:
|
||||
case Level::Warning:
|
||||
*stream_ << "warning: ";
|
||||
break;
|
||||
case DiagnosticLevel::Note:
|
||||
case Level::Note:
|
||||
*stream_ << "note: ";
|
||||
break;
|
||||
case DiagnosticLevel::LocationInfo:
|
||||
case Level::LocationInfo:
|
||||
break;
|
||||
}
|
||||
*stream_ << message.Format();
|
||||
@@ -39,15 +39,15 @@ auto StreamDiagnosticConsumer::HandleDiagnostic(Diagnostic diagnostic) -> void {
|
||||
// Don't include a snippet for location information to keep this diagnostic
|
||||
// more visually associated with the following diagnostic that it describes
|
||||
// and to better match C++ compilers.
|
||||
if (message.level != DiagnosticLevel::LocationInfo) {
|
||||
if (message.level != Level::LocationInfo) {
|
||||
message.loc.FormatSnippet(*stream_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto ConsoleDiagnosticConsumer() -> DiagnosticConsumer& {
|
||||
static auto* consumer = new StreamDiagnosticConsumer(&llvm::errs());
|
||||
auto ConsoleConsumer() -> Consumer& {
|
||||
static auto* consumer = new StreamConsumer(&llvm::errs());
|
||||
return *consumer;
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
@@ -9,25 +9,25 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
// Receives diagnostics as they are emitted.
|
||||
class DiagnosticConsumer {
|
||||
class Consumer {
|
||||
public:
|
||||
virtual ~DiagnosticConsumer() = default;
|
||||
virtual ~Consumer() = default;
|
||||
|
||||
// Handle a diagnostic.
|
||||
//
|
||||
// This relies on moves of the Diagnostic. At present, diagnostics are
|
||||
// allocated on the stack, so their lifetime is that of HandleDiagnostic.
|
||||
// However, SortingDiagnosticConsumer needs a longer lifetime, until all
|
||||
// However, SortingConsumer needs a longer lifetime, until all
|
||||
// diagnostics have been produced. As a consequence, it needs to either copy
|
||||
// or move the Diagnostic, and right now we're moving due to the overhead of
|
||||
// notes.
|
||||
//
|
||||
// At present, there is no persistent storage of diagnostics because IDEs
|
||||
// would be fine with diagnostics being printed immediately and discarded,
|
||||
// without SortingDiagnosticConsumer. If this becomes a performance issue, we
|
||||
// without SortingConsumer. If this becomes a performance issue, we
|
||||
// may want to investigate alternative ownership models that address both IDE
|
||||
// and CLI user needs.
|
||||
virtual auto HandleDiagnostic(Diagnostic diagnostic) -> void = 0;
|
||||
@@ -37,10 +37,9 @@ class DiagnosticConsumer {
|
||||
};
|
||||
|
||||
// A diagnostic consumer that prints to a stream.
|
||||
class StreamDiagnosticConsumer : public DiagnosticConsumer {
|
||||
class StreamConsumer : public Consumer {
|
||||
public:
|
||||
explicit StreamDiagnosticConsumer(llvm::raw_ostream* stream)
|
||||
: stream_(stream) {}
|
||||
explicit StreamConsumer(llvm::raw_ostream* stream) : stream_(stream) {}
|
||||
|
||||
auto HandleDiagnostic(Diagnostic diagnostic) -> void override;
|
||||
auto Flush() -> void override { stream_->flush(); }
|
||||
@@ -51,7 +50,7 @@ class StreamDiagnosticConsumer : public DiagnosticConsumer {
|
||||
}
|
||||
|
||||
private:
|
||||
auto Print(const DiagnosticMessage& message, llvm::StringRef prefix) -> void;
|
||||
auto Print(const Message& message, llvm::StringRef prefix) -> void;
|
||||
|
||||
llvm::raw_ostream* stream_;
|
||||
|
||||
@@ -63,17 +62,17 @@ class StreamDiagnosticConsumer : public DiagnosticConsumer {
|
||||
};
|
||||
|
||||
// Returns a diagnostic consumer instance that prints to stderr.
|
||||
auto ConsoleDiagnosticConsumer() -> DiagnosticConsumer&;
|
||||
auto ConsoleConsumer() -> Consumer&;
|
||||
|
||||
// Diagnostic consumer adaptor that tracks whether any errors have been
|
||||
// produced.
|
||||
class ErrorTrackingDiagnosticConsumer : public DiagnosticConsumer {
|
||||
class ErrorTrackingConsumer : public Consumer {
|
||||
public:
|
||||
explicit ErrorTrackingDiagnosticConsumer(DiagnosticConsumer& next_consumer)
|
||||
explicit ErrorTrackingConsumer(Consumer& next_consumer)
|
||||
: next_consumer_(&next_consumer) {}
|
||||
|
||||
auto HandleDiagnostic(Diagnostic diagnostic) -> void override {
|
||||
seen_error_ |= diagnostic.level == DiagnosticLevel::Error;
|
||||
seen_error_ |= diagnostic.level == Level::Error;
|
||||
next_consumer_->HandleDiagnostic(std::move(diagnostic));
|
||||
}
|
||||
|
||||
@@ -84,10 +83,10 @@ class ErrorTrackingDiagnosticConsumer : public DiagnosticConsumer {
|
||||
auto seen_error() const -> bool { return seen_error_; }
|
||||
|
||||
private:
|
||||
DiagnosticConsumer* next_consumer_;
|
||||
Consumer* next_consumer_;
|
||||
bool seen_error_ = false;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONSUMER_H_
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "toolchain/diagnostics/diagnostic_consumer.h"
|
||||
#include "toolchain/diagnostics/diagnostic_kind.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
namespace Internal {
|
||||
|
||||
@@ -30,13 +30,13 @@ using NoTypeDeduction = std::type_identity_t<Arg>;
|
||||
} // namespace Internal
|
||||
|
||||
template <typename LocT, typename AnnotateFn>
|
||||
class DiagnosticAnnotationScope;
|
||||
class AnnotationScope;
|
||||
|
||||
// The result of `DiagnosticConvert::ConvertLoc`. This is non-templated to allow
|
||||
// sharing across converters.
|
||||
struct ConvertedDiagnosticLoc {
|
||||
// Becomes DiagnosticMessage::loc.
|
||||
DiagnosticLoc loc;
|
||||
struct ConvertedLoc {
|
||||
// Becomes Message::loc.
|
||||
Loc loc;
|
||||
// Becomes Diagnostic::last_byte_offset.
|
||||
int32_t last_byte_offset;
|
||||
};
|
||||
@@ -46,10 +46,10 @@ struct ConvertedDiagnosticLoc {
|
||||
// write:
|
||||
//
|
||||
// struct NameId {
|
||||
// using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
// using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
// };
|
||||
template <typename StorageTypeT>
|
||||
struct DiagnosticTypeInfo {
|
||||
struct TypeInfo {
|
||||
using StorageType = StorageTypeT;
|
||||
};
|
||||
|
||||
@@ -62,10 +62,10 @@ struct DiagnosticTypeInfo {
|
||||
// when parsing, or a parse tree node when type-checking, and to allow unit
|
||||
// tests to be decoupled from any concrete location representation.
|
||||
template <typename LocT>
|
||||
class DiagnosticEmitter {
|
||||
class Emitter {
|
||||
public:
|
||||
// A builder-pattern type to provide a fluent interface for constructing
|
||||
// a more complex diagnostic. See `DiagnosticEmitter::Build` for the
|
||||
// a more complex diagnostic. See `Emitter::Build` for the
|
||||
// expected usage.
|
||||
// This is nodiscard to protect against accidentally building a diagnostic
|
||||
// without emitting it.
|
||||
@@ -77,14 +77,14 @@ class DiagnosticEmitter {
|
||||
-> DiagnosticBuilder& = default;
|
||||
|
||||
// Adds a note diagnostic attached to the main diagnostic being built.
|
||||
// The API mirrors the main emission API: `DiagnosticEmitter::Emit`.
|
||||
// For the expected usage see the builder API: `DiagnosticEmitter::Build`.
|
||||
// The API mirrors the main emission API: `Emitter::Emit`.
|
||||
// For the expected usage see the builder API: `Emitter::Build`.
|
||||
template <typename... Args>
|
||||
auto Note(LocT loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
Internal::NoTypeDeduction<Args>... args) -> DiagnosticBuilder&;
|
||||
|
||||
// Emits the built diagnostic and its attached notes.
|
||||
// For the expected usage see the builder API: `DiagnosticEmitter::Build`.
|
||||
// For the expected usage see the builder API: `Emitter::Build`.
|
||||
template <typename... Args>
|
||||
auto Emit() & -> void;
|
||||
|
||||
@@ -98,10 +98,10 @@ class DiagnosticEmitter {
|
||||
explicit operator bool() { return emitter_; }
|
||||
|
||||
private:
|
||||
friend class DiagnosticEmitter<LocT>;
|
||||
friend class Emitter<LocT>;
|
||||
|
||||
template <typename... Args>
|
||||
explicit DiagnosticBuilder(DiagnosticEmitter<LocT>* emitter, LocT loc,
|
||||
explicit DiagnosticBuilder(Emitter<LocT>* emitter, LocT loc,
|
||||
const DiagnosticBase<Args...>& diagnostic_base,
|
||||
llvm::SmallVector<llvm::Any> args);
|
||||
|
||||
@@ -116,30 +116,29 @@ class DiagnosticEmitter {
|
||||
llvm::SmallVector<llvm::Any> args) -> void;
|
||||
|
||||
// Adds a message to the diagnostic, handling conversion of the arguments. A
|
||||
// DiagnosticLoc must be provided instead of a LocT in order to
|
||||
// Loc must be provided instead of a LocT in order to
|
||||
// avoid potential recursion.
|
||||
template <typename... Args>
|
||||
auto AddMessageWithDiagnosticLoc(
|
||||
DiagnosticLoc loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
llvm::SmallVector<llvm::Any> args) -> void;
|
||||
auto AddMessageWithLoc(Loc loc,
|
||||
const DiagnosticBase<Args...>& diagnostic_base,
|
||||
llvm::SmallVector<llvm::Any> args) -> void;
|
||||
|
||||
// Handles the cast of llvm::Any to Args types for formatv.
|
||||
// TODO: Custom formatting can be provided with an format_provider, but that
|
||||
// affects all formatv calls. Consider replacing formatv with a custom call
|
||||
// that allows diagnostic-specific formatting.
|
||||
template <typename... Args, size_t... N>
|
||||
static auto FormatFn(const DiagnosticMessage& message,
|
||||
static auto FormatFn(const Message& message,
|
||||
std::index_sequence<N...> /*indices*/) -> std::string;
|
||||
|
||||
DiagnosticEmitter<LocT>* emitter_;
|
||||
Emitter<LocT>* emitter_;
|
||||
Diagnostic diagnostic_;
|
||||
};
|
||||
|
||||
// `consumer` is required to outlive the diagnostic emitter.
|
||||
explicit DiagnosticEmitter(DiagnosticConsumer* consumer)
|
||||
: consumer_(consumer) {}
|
||||
explicit Emitter(Consumer* consumer) : consumer_(consumer) {}
|
||||
|
||||
virtual ~DiagnosticEmitter() = default;
|
||||
virtual ~Emitter() = default;
|
||||
|
||||
// Emits an error.
|
||||
//
|
||||
@@ -165,16 +164,16 @@ class DiagnosticEmitter {
|
||||
|
||||
protected:
|
||||
// Callback type used to report context messages from ConvertLoc.
|
||||
// Note that the first parameter type is DiagnosticLoc rather than
|
||||
// Note that the first parameter type is Loc rather than
|
||||
// LocT, because ConvertLoc must not recurse.
|
||||
using ContextFnT =
|
||||
llvm::function_ref<auto(DiagnosticLoc, const DiagnosticBase<>&)->void>;
|
||||
llvm::function_ref<auto(Loc, const DiagnosticBase<>&)->void>;
|
||||
|
||||
// Converts a LocT to a DiagnosticLoc and its `last_byte_offset` (see
|
||||
// `DiagnosticMessage`). ConvertLoc may invoke context_fn to provide context
|
||||
// Converts a LocT to a Loc and its `last_byte_offset` (see
|
||||
// `Message`). ConvertLoc may invoke context_fn to provide context
|
||||
// messages.
|
||||
virtual auto ConvertLoc(LocT loc, ContextFnT context_fn) const
|
||||
-> ConvertedDiagnosticLoc = 0;
|
||||
-> ConvertedLoc = 0;
|
||||
|
||||
// Converts arg types as needed. Most children don't customize conversion, so
|
||||
// the default returns the argument unchanged.
|
||||
@@ -187,35 +186,35 @@ class DiagnosticEmitter {
|
||||
auto MakeAny(Arg arg) -> llvm::Any;
|
||||
|
||||
template <typename OtherLocT, typename AnnotateFn>
|
||||
friend class DiagnosticAnnotationScope;
|
||||
friend class AnnotationScope;
|
||||
|
||||
DiagnosticConsumer* consumer_;
|
||||
Consumer* consumer_;
|
||||
llvm::SmallVector<llvm::function_ref<auto(DiagnosticBuilder& builder)->void>>
|
||||
annotate_fns_;
|
||||
};
|
||||
|
||||
// This relies on `void*` location handling on `DiagnosticEmitter`.
|
||||
// This relies on `void*` location handling on `Emitter`.
|
||||
//
|
||||
// TODO: Based on how this ends up used or if we get more distinct emitters, it
|
||||
// might be worth considering having diagnostics specify that they don't apply
|
||||
// to source-location carrying emitters. For example, this might look like a
|
||||
// `CARBON_NO_LOC_DIAGNOSTIC` macro, or some other factoring. But it might end
|
||||
// up being more noise than it is worth.
|
||||
class NoLocDiagnosticEmitter : public DiagnosticEmitter<void*> {
|
||||
class NoLocEmitter : public Emitter<void*> {
|
||||
public:
|
||||
using DiagnosticEmitter::DiagnosticEmitter;
|
||||
using Emitter::Emitter;
|
||||
|
||||
// Emits an error. This specialization only applies to
|
||||
// `NoLocDiagnosticEmitter`.
|
||||
// `NoLocEmitter`.
|
||||
template <typename... Args>
|
||||
auto Emit(const DiagnosticBase<Args...>& diagnostic_base,
|
||||
Internal::NoTypeDeduction<Args>... args) -> void {
|
||||
DiagnosticEmitter::Emit(nullptr, diagnostic_base, args...);
|
||||
Emitter::Emit(nullptr, diagnostic_base, args...);
|
||||
}
|
||||
|
||||
protected:
|
||||
auto ConvertLoc(void* /*loc*/, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> ConvertedLoc override {
|
||||
return {.loc = {.filename = ""}, .last_byte_offset = -1};
|
||||
}
|
||||
};
|
||||
@@ -228,24 +227,23 @@ class NoLocDiagnosticEmitter : public DiagnosticEmitter<void*> {
|
||||
// given emitter. That function can annotate the diagnostic by calling
|
||||
// `builder.Note` to add notes.
|
||||
template <typename LocT, typename AnnotateFn>
|
||||
class DiagnosticAnnotationScope {
|
||||
class AnnotationScope {
|
||||
public:
|
||||
DiagnosticAnnotationScope(DiagnosticEmitter<LocT>* emitter,
|
||||
AnnotateFn annotate)
|
||||
AnnotationScope(Emitter<LocT>* emitter, AnnotateFn annotate)
|
||||
: emitter_(emitter), annotate_(std::move(annotate)) {
|
||||
emitter_->annotate_fns_.push_back(annotate_);
|
||||
}
|
||||
~DiagnosticAnnotationScope() { emitter_->annotate_fns_.pop_back(); }
|
||||
~AnnotationScope() { emitter_->annotate_fns_.pop_back(); }
|
||||
|
||||
private:
|
||||
DiagnosticEmitter<LocT>* emitter_;
|
||||
Emitter<LocT>* emitter_;
|
||||
// Make a copy of the annotation function to ensure that it lives long enough.
|
||||
AnnotateFn annotate_;
|
||||
};
|
||||
|
||||
template <typename LocT, typename AnnotateFn>
|
||||
DiagnosticAnnotationScope(DiagnosticEmitter<LocT>* emitter, AnnotateFn annotate)
|
||||
-> DiagnosticAnnotationScope<LocT, AnnotateFn>;
|
||||
AnnotationScope(Emitter<LocT>* emitter, AnnotateFn annotate)
|
||||
-> AnnotationScope<LocT, AnnotateFn>;
|
||||
|
||||
// ============================================================================
|
||||
// Only internal implementation details below this point.
|
||||
@@ -254,13 +252,13 @@ DiagnosticAnnotationScope(DiagnosticEmitter<LocT>* emitter, AnnotateFn annotate)
|
||||
namespace Internal {
|
||||
|
||||
// Determines whether there's a DiagnosticType member on Arg.
|
||||
// Used by DiagnosticEmitter.
|
||||
// Used by Emitter.
|
||||
template <typename Arg>
|
||||
concept HasDiagnosticType = requires { typename Arg::DiagnosticType; };
|
||||
|
||||
// The default implementation with no conversion.
|
||||
template <typename Arg>
|
||||
struct DiagnosticTypeForArg : public DiagnosticTypeInfo<Arg> {};
|
||||
struct DiagnosticTypeForArg : public TypeInfo<Arg> {};
|
||||
|
||||
// Exposes a custom conversion for an argument type.
|
||||
template <typename Arg>
|
||||
@@ -271,14 +269,14 @@ struct DiagnosticTypeForArg<Arg> : public Arg::DiagnosticType {};
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Note(
|
||||
auto Emitter<LocT>::DiagnosticBuilder::Note(
|
||||
LocT loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
Internal::NoTypeDeduction<Args>... args) -> DiagnosticBuilder& {
|
||||
if (!emitter_) {
|
||||
return *this;
|
||||
}
|
||||
CARBON_CHECK(diagnostic_base.Level == DiagnosticLevel::Note ||
|
||||
diagnostic_base.Level == DiagnosticLevel::LocationInfo,
|
||||
CARBON_CHECK(diagnostic_base.Level == Level::Note ||
|
||||
diagnostic_base.Level == Level::LocationInfo,
|
||||
"{0}", static_cast<int>(diagnostic_base.Level));
|
||||
AddMessage(loc, diagnostic_base, {emitter_->MakeAny<Args>(args)...});
|
||||
return *this;
|
||||
@@ -286,7 +284,7 @@ auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Note(
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Emit() & -> void {
|
||||
auto Emitter<LocT>::DiagnosticBuilder::Emit() & -> void {
|
||||
if (!emitter_) {
|
||||
return;
|
||||
}
|
||||
@@ -303,7 +301,7 @@ concept AlwaysFalse = false;
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Emit() && -> void {
|
||||
auto Emitter<LocT>::DiagnosticBuilder::Emit() && -> void {
|
||||
// TODO: This is required by clang-16, but `false` may work in newer clang
|
||||
// versions. Replace when possible.
|
||||
static_assert(Internal::AlwaysFalse<LocT>,
|
||||
@@ -314,59 +312,59 @@ auto DiagnosticEmitter<LocT>::DiagnosticBuilder::Emit() && -> void {
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
DiagnosticEmitter<LocT>::DiagnosticBuilder::DiagnosticBuilder(
|
||||
DiagnosticEmitter<LocT>* emitter, LocT loc,
|
||||
Emitter<LocT>::DiagnosticBuilder::DiagnosticBuilder(
|
||||
Emitter<LocT>* emitter, LocT loc,
|
||||
const DiagnosticBase<Args...>& diagnostic_base,
|
||||
llvm::SmallVector<llvm::Any> args)
|
||||
: emitter_(emitter), diagnostic_({.level = diagnostic_base.Level}) {
|
||||
AddMessage(loc, diagnostic_base, std::move(args));
|
||||
CARBON_CHECK(diagnostic_base.Level != DiagnosticLevel::Note);
|
||||
CARBON_CHECK(diagnostic_base.Level != Level::Note);
|
||||
}
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::AddMessage(
|
||||
auto Emitter<LocT>::DiagnosticBuilder::AddMessage(
|
||||
LocT loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
llvm::SmallVector<llvm::Any> args) -> void {
|
||||
if (!emitter_) {
|
||||
return;
|
||||
}
|
||||
auto converted = emitter_->ConvertLoc(
|
||||
loc, [&](DiagnosticLoc context_loc,
|
||||
const DiagnosticBase<>& context_diagnostic_base) {
|
||||
AddMessageWithDiagnosticLoc(context_loc, context_diagnostic_base, {});
|
||||
loc,
|
||||
[&](Loc context_loc, const DiagnosticBase<>& context_diagnostic_base) {
|
||||
AddMessageWithLoc(context_loc, context_diagnostic_base, {});
|
||||
});
|
||||
// Use the last byte offset from the first message.
|
||||
if (diagnostic_.messages.empty()) {
|
||||
diagnostic_.last_byte_offset = converted.last_byte_offset;
|
||||
}
|
||||
AddMessageWithDiagnosticLoc(converted.loc, diagnostic_base, args);
|
||||
AddMessageWithLoc(converted.loc, diagnostic_base, args);
|
||||
}
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::AddMessageWithDiagnosticLoc(
|
||||
DiagnosticLoc loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
auto Emitter<LocT>::DiagnosticBuilder::AddMessageWithLoc(
|
||||
Loc loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
llvm::SmallVector<llvm::Any> args) -> void {
|
||||
if (!emitter_) {
|
||||
return;
|
||||
}
|
||||
diagnostic_.messages.emplace_back(DiagnosticMessage{
|
||||
.kind = diagnostic_base.Kind,
|
||||
.level = diagnostic_base.Level,
|
||||
.loc = loc,
|
||||
.format = diagnostic_base.Format,
|
||||
.format_args = std::move(args),
|
||||
.format_fn = [](const DiagnosticMessage& message) -> std::string {
|
||||
return FormatFn<Args...>(message,
|
||||
std::make_index_sequence<sizeof...(Args)>());
|
||||
}});
|
||||
diagnostic_.messages.emplace_back(
|
||||
Message{.kind = diagnostic_base.Kind,
|
||||
.level = diagnostic_base.Level,
|
||||
.loc = loc,
|
||||
.format = diagnostic_base.Format,
|
||||
.format_args = std::move(args),
|
||||
.format_fn = [](const Message& message) -> std::string {
|
||||
return FormatFn<Args...>(
|
||||
message, std::make_index_sequence<sizeof...(Args)>());
|
||||
}});
|
||||
}
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args, size_t... N>
|
||||
auto DiagnosticEmitter<LocT>::DiagnosticBuilder::FormatFn(
|
||||
const DiagnosticMessage& message, std::index_sequence<N...> /*indices*/)
|
||||
auto Emitter<LocT>::DiagnosticBuilder::FormatFn(
|
||||
const Message& message, std::index_sequence<N...> /*indices*/)
|
||||
-> std::string {
|
||||
static_assert(sizeof...(Args) == sizeof...(N), "Invalid template args");
|
||||
CARBON_CHECK(message.format_args.size() == sizeof...(Args),
|
||||
@@ -381,9 +379,9 @@ auto DiagnosticEmitter<LocT>::DiagnosticBuilder::FormatFn(
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
auto DiagnosticEmitter<LocT>::Emit(
|
||||
LocT loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
Internal::NoTypeDeduction<Args>... args) -> void {
|
||||
auto Emitter<LocT>::Emit(LocT loc,
|
||||
const DiagnosticBase<Args...>& diagnostic_base,
|
||||
Internal::NoTypeDeduction<Args>... args) -> void {
|
||||
DiagnosticBuilder builder(this, loc, diagnostic_base,
|
||||
{MakeAny<Args>(args)...});
|
||||
builder.Emit();
|
||||
@@ -391,16 +389,17 @@ auto DiagnosticEmitter<LocT>::Emit(
|
||||
|
||||
template <typename LocT>
|
||||
template <typename... Args>
|
||||
auto DiagnosticEmitter<LocT>::Build(
|
||||
LocT loc, const DiagnosticBase<Args...>& diagnostic_base,
|
||||
Internal::NoTypeDeduction<Args>... args) -> DiagnosticBuilder {
|
||||
auto Emitter<LocT>::Build(LocT loc,
|
||||
const DiagnosticBase<Args...>& diagnostic_base,
|
||||
Internal::NoTypeDeduction<Args>... args)
|
||||
-> DiagnosticBuilder {
|
||||
return DiagnosticBuilder(this, loc, diagnostic_base,
|
||||
{MakeAny<Args>(args)...});
|
||||
}
|
||||
|
||||
template <typename LocT>
|
||||
template <typename Arg>
|
||||
auto DiagnosticEmitter<LocT>::MakeAny(Arg arg) -> llvm::Any {
|
||||
auto Emitter<LocT>::MakeAny(Arg arg) -> llvm::Any {
|
||||
llvm::Any converted = ConvertArg(arg);
|
||||
using Storage = Internal::DiagnosticTypeForArg<Arg>::StorageType;
|
||||
CARBON_CHECK(llvm::any_cast<Storage>(&converted),
|
||||
@@ -409,6 +408,6 @@ auto DiagnosticEmitter<LocT>::MakeAny(Arg arg) -> llvm::Any {
|
||||
return converted;
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_EMITTER_H_
|
||||
|
||||
@@ -13,72 +13,70 @@
|
||||
namespace Carbon::Testing {
|
||||
namespace {
|
||||
|
||||
using ::Carbon::Testing::IsDiagnostic;
|
||||
using ::Carbon::Testing::IsSingleDiagnostic;
|
||||
using testing::ElementsAre;
|
||||
|
||||
class FakeDiagnosticEmitter : public DiagnosticEmitter<int> {
|
||||
class FakeEmitter : public Diagnostics::Emitter<int> {
|
||||
public:
|
||||
using DiagnosticEmitter::DiagnosticEmitter;
|
||||
using Emitter::Emitter;
|
||||
|
||||
protected:
|
||||
auto ConvertLoc(int n, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> Diagnostics::ConvertedLoc override {
|
||||
return {.loc = {.line_number = 1, .column_number = n},
|
||||
.last_byte_offset = -1};
|
||||
}
|
||||
};
|
||||
|
||||
class DiagnosticEmitterTest : public ::testing::Test {
|
||||
class EmitterTest : public ::testing::Test {
|
||||
public:
|
||||
DiagnosticEmitterTest() : emitter_(&consumer_) {}
|
||||
EmitterTest() : emitter_(&consumer_) {}
|
||||
|
||||
Testing::MockDiagnosticConsumer consumer_;
|
||||
FakeDiagnosticEmitter emitter_;
|
||||
FakeEmitter emitter_;
|
||||
};
|
||||
|
||||
TEST_F(DiagnosticEmitterTest, EmitSimpleError) {
|
||||
TEST_F(EmitterTest, EmitSimpleError) {
|
||||
CARBON_DIAGNOSTIC(TestDiagnostic, Error, "simple error");
|
||||
EXPECT_CALL(consumer_, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, 1, 1, "simple error")));
|
||||
Diagnostics::Kind::TestDiagnostic,
|
||||
Diagnostics::Level::Error, 1, 1, "simple error")));
|
||||
EXPECT_CALL(consumer_, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, 1, 2, "simple error")));
|
||||
Diagnostics::Kind::TestDiagnostic,
|
||||
Diagnostics::Level::Error, 1, 2, "simple error")));
|
||||
emitter_.Emit(1, TestDiagnostic);
|
||||
emitter_.Emit(2, TestDiagnostic);
|
||||
}
|
||||
|
||||
TEST_F(DiagnosticEmitterTest, EmitSimpleWarning) {
|
||||
TEST_F(EmitterTest, EmitSimpleWarning) {
|
||||
CARBON_DIAGNOSTIC(TestDiagnostic, Warning, "simple warning");
|
||||
EXPECT_CALL(consumer_,
|
||||
HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic, DiagnosticLevel::Warning, 1,
|
||||
1, "simple warning")));
|
||||
Diagnostics::Kind::TestDiagnostic,
|
||||
Diagnostics::Level::Warning, 1, 1, "simple warning")));
|
||||
emitter_.Emit(1, TestDiagnostic);
|
||||
}
|
||||
|
||||
TEST_F(DiagnosticEmitterTest, EmitOneArgDiagnostic) {
|
||||
TEST_F(EmitterTest, EmitOneArgDiagnostic) {
|
||||
CARBON_DIAGNOSTIC(TestDiagnostic, Error, "arg: `{0}`", std::string);
|
||||
EXPECT_CALL(consumer_, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, 1, 1, "arg: `str`")));
|
||||
Diagnostics::Kind::TestDiagnostic,
|
||||
Diagnostics::Level::Error, 1, 1, "arg: `str`")));
|
||||
emitter_.Emit(1, TestDiagnostic, "str");
|
||||
}
|
||||
|
||||
TEST_F(DiagnosticEmitterTest, EmitNote) {
|
||||
TEST_F(EmitterTest, EmitNote) {
|
||||
CARBON_DIAGNOSTIC(TestDiagnostic, Warning, "simple warning");
|
||||
CARBON_DIAGNOSTIC(TestDiagnosticNote, Note, "note");
|
||||
EXPECT_CALL(
|
||||
consumer_,
|
||||
HandleDiagnostic(IsDiagnostic(
|
||||
DiagnosticLevel::Warning,
|
||||
Diagnostics::Level::Warning,
|
||||
ElementsAre(
|
||||
IsDiagnosticMessage(DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Warning, 1, 1,
|
||||
IsDiagnosticMessage(Diagnostics::Kind::TestDiagnostic,
|
||||
Diagnostics::Level::Warning, 1, 1,
|
||||
"simple warning"),
|
||||
IsDiagnosticMessage(DiagnosticKind::TestDiagnosticNote,
|
||||
DiagnosticLevel::Note, 1, 2, "note")))));
|
||||
IsDiagnosticMessage(Diagnostics::Kind::TestDiagnosticNote,
|
||||
Diagnostics::Level::Note, 1, 2, "note")))));
|
||||
emitter_.Build(1, TestDiagnostic).Note(2, TestDiagnosticNote).Emit();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
#include "toolchain/diagnostics/diagnostic_kind.h" // IWYU pragma: keep
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
CARBON_DEFINE_ENUM_CLASS_NAMES(DiagnosticKind) = {
|
||||
CARBON_DEFINE_ENUM_CLASS_NAMES(Kind) = {
|
||||
#define CARBON_DIAGNOSTIC_KIND(Name) CARBON_ENUM_CLASS_NAME_STRING(Name)
|
||||
#include "toolchain/diagnostics/diagnostic_kind.def"
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
|
||||
#include "common/enum_base.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
// Although this currently fits into int8_t, it shouldn't be expected to
|
||||
// long-term.
|
||||
// NOLINTNEXTLINE(performance-enum-size)
|
||||
CARBON_DEFINE_RAW_ENUM_CLASS(DiagnosticKind, uint16_t) {
|
||||
CARBON_DEFINE_RAW_ENUM_CLASS(Kind, uint16_t) {
|
||||
#define CARBON_DIAGNOSTIC_KIND(Name) CARBON_RAW_ENUM_ENUMERATOR(Name)
|
||||
#include "toolchain/diagnostics/diagnostic_kind.def"
|
||||
};
|
||||
@@ -27,19 +27,18 @@ CARBON_DEFINE_RAW_ENUM_CLASS(DiagnosticKind, uint16_t) {
|
||||
// definitions centrally is expected to create a compilation bottleneck
|
||||
// long-term, and we also see value to keeping diagnostic format strings close
|
||||
// to the consuming code.
|
||||
class DiagnosticKind : public CARBON_ENUM_BASE(DiagnosticKind) {
|
||||
class Kind : public CARBON_ENUM_BASE(Kind) {
|
||||
public:
|
||||
#define CARBON_DIAGNOSTIC_KIND(Name) CARBON_ENUM_CONSTANT_DECL(Name)
|
||||
#include "toolchain/diagnostics/diagnostic_kind.def"
|
||||
};
|
||||
|
||||
#define CARBON_DIAGNOSTIC_KIND(Name) \
|
||||
CARBON_ENUM_CONSTANT_DEFINITION(DiagnosticKind, Name)
|
||||
#define CARBON_DIAGNOSTIC_KIND(Name) CARBON_ENUM_CONSTANT_DEFINITION(Kind, Name)
|
||||
#include "toolchain/diagnostics/diagnostic_kind.def"
|
||||
|
||||
// We expect DiagnosticKind to fit into 2 bits.
|
||||
static_assert(sizeof(DiagnosticKind) == 2, "DiagnosticKind includes padding!");
|
||||
// We expect Kind to fit into 2 bits.
|
||||
static_assert(sizeof(Kind) == 2, "Kind includes padding!");
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_KIND_H_
|
||||
|
||||
@@ -7,26 +7,26 @@
|
||||
|
||||
#include "toolchain/diagnostics/diagnostic_emitter.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
// We frequently want a `DiagnosticEmitter` that directly uses a filename. Note
|
||||
// We frequently want a `Emitter` that directly uses a filename. Note
|
||||
// that an empty string can be used for a diagnostic that has no particular
|
||||
// location.
|
||||
//
|
||||
// Note this provides no way to set a line or column on diagnostics. More
|
||||
// specific emitters must be used for that.
|
||||
class FileDiagnosticEmitter : public DiagnosticEmitter<llvm::StringRef> {
|
||||
class FileEmitter : public Emitter<llvm::StringRef> {
|
||||
public:
|
||||
using DiagnosticEmitter::DiagnosticEmitter;
|
||||
using Emitter::Emitter;
|
||||
|
||||
protected:
|
||||
// Converts a filename directly to the diagnostic location.
|
||||
auto ConvertLoc(llvm::StringRef filename, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> ConvertedLoc override {
|
||||
return {.loc = {.filename = filename}, .last_byte_offset = -1};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_FILE_DIAGNOSTICS_H_
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include "common/check.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
|
||||
auto llvm::format_provider<Carbon::BoolAsSelect>::format(
|
||||
const Carbon::BoolAsSelect& wrapper, raw_ostream& out, StringRef style)
|
||||
-> void {
|
||||
auto llvm::format_provider<Carbon::Diagnostics::BoolAsSelect>::format(
|
||||
const Carbon::Diagnostics::BoolAsSelect& wrapper, raw_ostream& out,
|
||||
StringRef style) -> void {
|
||||
if (style.empty()) {
|
||||
llvm::format_provider<bool>::format(wrapper.value, out, style);
|
||||
return;
|
||||
@@ -30,9 +30,9 @@ auto llvm::format_provider<Carbon::BoolAsSelect>::format(
|
||||
}
|
||||
}
|
||||
|
||||
auto llvm::format_provider<Carbon::IntAsSelect>::format(
|
||||
const Carbon::IntAsSelect& wrapper, raw_ostream& out, StringRef style)
|
||||
-> void {
|
||||
auto llvm::format_provider<Carbon::Diagnostics::IntAsSelect>::format(
|
||||
const Carbon::Diagnostics::IntAsSelect& wrapper, raw_ostream& out,
|
||||
StringRef style) -> void {
|
||||
if (style == "s") {
|
||||
if (wrapper.value != 1) {
|
||||
out << "s";
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "common/ostream.h"
|
||||
#include "llvm/Support/FormatVariadicDetails.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
// Selects a formatv string based on the value.
|
||||
//
|
||||
@@ -53,20 +53,20 @@ struct IntAsSelect {
|
||||
int value;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
// See BoolAsSelect.
|
||||
// See Diagnostics::BoolAsSelect.
|
||||
template <>
|
||||
struct llvm::format_provider<Carbon::BoolAsSelect> {
|
||||
static auto format(const Carbon::BoolAsSelect& wrapper, raw_ostream& out,
|
||||
StringRef style) -> void;
|
||||
struct llvm::format_provider<Carbon::Diagnostics::BoolAsSelect> {
|
||||
static auto format(const Carbon::Diagnostics::BoolAsSelect& wrapper,
|
||||
raw_ostream& out, StringRef style) -> void;
|
||||
};
|
||||
|
||||
// See IntAsSelect.
|
||||
// See Diagnostics::IntAsSelect.
|
||||
template <>
|
||||
struct llvm::format_provider<Carbon::IntAsSelect> {
|
||||
static auto format(const Carbon::IntAsSelect& wrapper, raw_ostream& out,
|
||||
StringRef style) -> void;
|
||||
struct llvm::format_provider<Carbon::Diagnostics::IntAsSelect> {
|
||||
static auto format(const Carbon::Diagnostics::IntAsSelect& wrapper,
|
||||
raw_ostream& out, StringRef style) -> void;
|
||||
};
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_FORMAT_PROVIDERS_H_
|
||||
|
||||
@@ -9,72 +9,94 @@
|
||||
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
|
||||
TEST(BoolAsSelect, Cases) {
|
||||
constexpr char Format[] = "{0:a|b}";
|
||||
EXPECT_THAT(llvm::formatv(Format, BoolAsSelect(true)).str(), Eq("a"));
|
||||
EXPECT_THAT(llvm::formatv(Format, BoolAsSelect(false)).str(), Eq("b"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::BoolAsSelect(true)).str(),
|
||||
Eq("a"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::BoolAsSelect(false)).str(),
|
||||
Eq("b"));
|
||||
}
|
||||
|
||||
TEST(BoolAsSelect, CasesWithNormalFormat) {
|
||||
constexpr char Format[] = "{0} {0:a|b}";
|
||||
EXPECT_THAT(llvm::formatv(Format, BoolAsSelect(true)).str(), Eq("true a"));
|
||||
EXPECT_THAT(llvm::formatv(Format, BoolAsSelect(false)).str(), Eq("false b"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::BoolAsSelect(true)).str(),
|
||||
Eq("true a"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::BoolAsSelect(false)).str(),
|
||||
Eq("false b"));
|
||||
}
|
||||
|
||||
TEST(BoolAsSelect, Spaces) {
|
||||
constexpr char Format[] = "{0: a | b }";
|
||||
EXPECT_THAT(llvm::formatv(Format, BoolAsSelect(true)).str(), Eq(" a "));
|
||||
EXPECT_THAT(llvm::formatv(Format, BoolAsSelect(false)).str(), Eq(" b "));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::BoolAsSelect(true)).str(),
|
||||
Eq(" a "));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::BoolAsSelect(false)).str(),
|
||||
Eq(" b "));
|
||||
}
|
||||
|
||||
TEST(IntAsSelect, OnlyDefault) {
|
||||
constexpr char Format[] = "{0::default}";
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("default"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(0)).str(),
|
||||
Eq("default"));
|
||||
}
|
||||
|
||||
TEST(IntAsSelect, OneEquals) {
|
||||
constexpr char Format[] = "{0:=0:zero}";
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("zero"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(0)).str(),
|
||||
Eq("zero"));
|
||||
}
|
||||
|
||||
TEST(IntAsSelect, TwoEquals) {
|
||||
constexpr char Format[] = "{0:=0:zero|=1:one}";
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("zero"));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(1)).str(), Eq("one"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(0)).str(),
|
||||
Eq("zero"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(1)).str(),
|
||||
Eq("one"));
|
||||
}
|
||||
|
||||
TEST(IntAsSelect, TwoEqualsAndDefault) {
|
||||
constexpr char Format[] = "{0:=0:zero|=1:one|:default}";
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("zero"));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(1)).str(), Eq("one"));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(2)).str(), Eq("default"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(0)).str(),
|
||||
Eq("zero"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(1)).str(),
|
||||
Eq("one"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(2)).str(),
|
||||
Eq("default"));
|
||||
}
|
||||
|
||||
TEST(IntAsSelect, Spaces) {
|
||||
constexpr char Format[] = "{0:=0: zero |=1: one |: default }";
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq(" zero "));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(1)).str(), Eq(" one "));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(2)).str(), Eq(" default "));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(0)).str(),
|
||||
Eq(" zero "));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(1)).str(),
|
||||
Eq(" one "));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(2)).str(),
|
||||
Eq(" default "));
|
||||
}
|
||||
|
||||
TEST(IntAsSelect, CasesWithNormalFormat) {
|
||||
constexpr char Format[] = "{0} argument{0:=1:|:s}";
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("0 arguments"));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(1)).str(), Eq("1 argument"));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(2)).str(), Eq("2 arguments"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(0)).str(),
|
||||
Eq("0 arguments"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(1)).str(),
|
||||
Eq("1 argument"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(2)).str(),
|
||||
Eq("2 arguments"));
|
||||
}
|
||||
|
||||
TEST(IntAsSelect, PluralS) {
|
||||
constexpr char Format[] = "{0} argument{0:s}";
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(0)).str(), Eq("0 arguments"));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(1)).str(), Eq("1 argument"));
|
||||
EXPECT_THAT(llvm::formatv(Format, IntAsSelect(2)).str(), Eq("2 arguments"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(0)).str(),
|
||||
Eq("0 arguments"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(1)).str(),
|
||||
Eq("1 argument"));
|
||||
EXPECT_THAT(llvm::formatv(Format, Diagnostics::IntAsSelect(2)).str(),
|
||||
Eq("2 arguments"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "toolchain/diagnostics/mocks.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
auto PrintTo(const Diagnostic& diagnostic, std::ostream* os) -> void {
|
||||
*os << "Diagnostic{";
|
||||
@@ -17,21 +17,21 @@ auto PrintTo(const Diagnostic& diagnostic, std::ostream* os) -> void {
|
||||
*os << "\"}";
|
||||
}
|
||||
|
||||
auto PrintTo(DiagnosticLevel level, std::ostream* os) -> void {
|
||||
auto PrintTo(Level level, std::ostream* os) -> void {
|
||||
switch (level) {
|
||||
case DiagnosticLevel::LocationInfo:
|
||||
case Level::LocationInfo:
|
||||
*os << "LocationInfo";
|
||||
break;
|
||||
case DiagnosticLevel::Note:
|
||||
case Level::Note:
|
||||
*os << "Note";
|
||||
break;
|
||||
case DiagnosticLevel::Warning:
|
||||
case Level::Warning:
|
||||
*os << "Warning";
|
||||
break;
|
||||
case DiagnosticLevel::Error:
|
||||
case Level::Error:
|
||||
*os << "Error";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
@@ -11,51 +11,53 @@
|
||||
|
||||
namespace Carbon::Testing {
|
||||
|
||||
class MockDiagnosticConsumer : public DiagnosticConsumer {
|
||||
class MockDiagnosticConsumer : public Diagnostics::Consumer {
|
||||
public:
|
||||
MOCK_METHOD(void, HandleDiagnostic, (Diagnostic diagnostic), (override));
|
||||
MOCK_METHOD(void, HandleDiagnostic, (Diagnostics::Diagnostic diagnostic),
|
||||
(override));
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(modernize-use-trailing-return-type): From the macro.
|
||||
MATCHER_P(IsDiagnosticMessageString, matcher, "") {
|
||||
const DiagnosticMessage& message = arg;
|
||||
MATCHER_P(IsDiagnosticsMessageString, matcher, "") {
|
||||
const Diagnostics::Message& message = arg;
|
||||
return testing::ExplainMatchResult(matcher, message.Format(),
|
||||
result_listener);
|
||||
}
|
||||
|
||||
inline auto IsDiagnosticMessage(testing::Matcher<DiagnosticKind> kind,
|
||||
testing::Matcher<DiagnosticLevel> level,
|
||||
inline auto IsDiagnosticMessage(testing::Matcher<Diagnostics::Kind> kind,
|
||||
testing::Matcher<Diagnostics::Level> level,
|
||||
testing::Matcher<int> line_number,
|
||||
testing::Matcher<int> column_number,
|
||||
testing::Matcher<std::string> message)
|
||||
-> testing::Matcher<DiagnosticMessage> {
|
||||
-> testing::Matcher<Diagnostics::Message> {
|
||||
using testing::AllOf;
|
||||
using testing::Field;
|
||||
return AllOf(Field("kind", &DiagnosticMessage::kind, kind),
|
||||
Field("level", &DiagnosticMessage::level, level),
|
||||
Field(&DiagnosticMessage::loc,
|
||||
AllOf(Field("line_number", &DiagnosticLoc::line_number,
|
||||
line_number),
|
||||
Field("column_number", &DiagnosticLoc::column_number,
|
||||
column_number))),
|
||||
IsDiagnosticMessageString(message));
|
||||
return AllOf(
|
||||
Field("kind", &Diagnostics::Message::kind, kind),
|
||||
Field("level", &Diagnostics::Message::level, level),
|
||||
Field(&Diagnostics::Message::loc,
|
||||
AllOf(Field("line_number", &Diagnostics::Loc::line_number,
|
||||
line_number),
|
||||
Field("column_number", &Diagnostics::Loc::column_number,
|
||||
column_number))),
|
||||
IsDiagnosticsMessageString(message));
|
||||
}
|
||||
|
||||
inline auto IsDiagnostic(
|
||||
testing::Matcher<DiagnosticLevel> level,
|
||||
testing::Matcher<llvm::SmallVector<DiagnosticMessage>> elements)
|
||||
-> testing::Matcher<Diagnostic> {
|
||||
testing::Matcher<Diagnostics::Level> level,
|
||||
testing::Matcher<llvm::SmallVector<Diagnostics::Message>> elements)
|
||||
-> testing::Matcher<Diagnostics::Diagnostic> {
|
||||
return testing::AllOf(
|
||||
testing::Field("level", &Diagnostic::level, level),
|
||||
testing::Field("messages", &Diagnostic::messages, elements));
|
||||
testing::Field("level", &Diagnostics::Diagnostic::level, level),
|
||||
testing::Field("messages", &Diagnostics::Diagnostic::messages, elements));
|
||||
}
|
||||
|
||||
inline auto IsSingleDiagnostic(testing::Matcher<DiagnosticKind> kind,
|
||||
testing::Matcher<DiagnosticLevel> level,
|
||||
inline auto IsSingleDiagnostic(testing::Matcher<Diagnostics::Kind> kind,
|
||||
testing::Matcher<Diagnostics::Level> level,
|
||||
testing::Matcher<int> line_number,
|
||||
testing::Matcher<int> column_number,
|
||||
testing::Matcher<std::string> message)
|
||||
-> testing::Matcher<Diagnostic> {
|
||||
-> testing::Matcher<Diagnostics::Diagnostic> {
|
||||
return IsDiagnostic(
|
||||
level, testing::ElementsAre(IsDiagnosticMessage(kind, level, line_number,
|
||||
column_number, message)));
|
||||
@@ -63,12 +65,12 @@ inline auto IsSingleDiagnostic(testing::Matcher<DiagnosticKind> kind,
|
||||
|
||||
} // namespace Carbon::Testing
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
// Printing helpers for tests.
|
||||
auto PrintTo(const Diagnostic& diagnostic, std::ostream* os) -> void;
|
||||
auto PrintTo(DiagnosticLevel level, std::ostream* os) -> void;
|
||||
auto PrintTo(Level level, std::ostream* os) -> void;
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_MOCKS_H_
|
||||
|
||||
@@ -7,37 +7,37 @@
|
||||
|
||||
#include "toolchain/diagnostics/diagnostic_emitter.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
// Returns a singleton consumer that doesn't print its diagnostics.
|
||||
inline auto NullDiagnosticConsumer() -> DiagnosticConsumer& {
|
||||
struct Consumer : DiagnosticConsumer {
|
||||
inline auto NullConsumer() -> Consumer& {
|
||||
struct SingletonConsumer : Consumer {
|
||||
auto HandleDiagnostic(Diagnostic /*d*/) -> void override {}
|
||||
};
|
||||
static auto* consumer = new Consumer;
|
||||
static auto* consumer = new SingletonConsumer;
|
||||
return *consumer;
|
||||
}
|
||||
|
||||
// Returns a singleton emitter that doesn't print its diagnostics.
|
||||
template <typename LocT>
|
||||
inline auto NullDiagnosticEmitter() -> DiagnosticEmitter<LocT>& {
|
||||
class Emitter : public DiagnosticEmitter<LocT> {
|
||||
inline auto NullEmitter() -> Emitter<LocT>& {
|
||||
class SingletonEmitter : public Emitter<LocT> {
|
||||
public:
|
||||
using DiagnosticEmitter<LocT>::DiagnosticEmitter;
|
||||
using Emitter<LocT>::Emitter;
|
||||
|
||||
protected:
|
||||
// Converts a filename directly to the diagnostic location.
|
||||
auto ConvertLoc(LocT /*loc*/,
|
||||
DiagnosticEmitter<LocT>::ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
Emitter<LocT>::ContextFnT /*context_fn*/) const
|
||||
-> ConvertedLoc override {
|
||||
return {.loc = {}, .last_byte_offset = -1};
|
||||
}
|
||||
};
|
||||
|
||||
static auto* emitter = new Emitter(&NullDiagnosticConsumer());
|
||||
static auto* emitter = new SingletonEmitter(&NullConsumer());
|
||||
return *emitter;
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_NULL_DIAGNOSTICS_H_
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "toolchain/diagnostics/diagnostic_emitter.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
|
||||
// Buffers incoming diagnostics for printing and sorting.
|
||||
//
|
||||
@@ -19,12 +19,12 @@ namespace Carbon {
|
||||
// `Diagnostic::messages[0]` will always be a location in the consumer's primary
|
||||
// file, but if it needs to correspond to a different file, the
|
||||
// `last_byte_offset` must still indicate an offset within the primary file.
|
||||
class SortingDiagnosticConsumer : public DiagnosticConsumer {
|
||||
class SortingConsumer : public Consumer {
|
||||
public:
|
||||
explicit SortingDiagnosticConsumer(DiagnosticConsumer& next_consumer)
|
||||
explicit SortingConsumer(Consumer& next_consumer)
|
||||
: next_consumer_(&next_consumer) {}
|
||||
|
||||
~SortingDiagnosticConsumer() override {
|
||||
~SortingConsumer() override {
|
||||
// We choose not to automatically flush diagnostics here, because they are
|
||||
// likely to refer to data that gets destroyed before the diagnostics
|
||||
// consumer is destroyed, because the diagnostics consumer is typically
|
||||
@@ -55,9 +55,9 @@ class SortingDiagnosticConsumer : public DiagnosticConsumer {
|
||||
// specify 0.
|
||||
llvm::SmallVector<Diagnostic, 0> diagnostics_;
|
||||
|
||||
DiagnosticConsumer* next_consumer_;
|
||||
Consumer* next_consumer_;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_SORTING_DIAGNOSTIC_CONSUMER_H_
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "toolchain/diagnostics/diagnostic_emitter.h"
|
||||
#include "toolchain/diagnostics/mocks.h"
|
||||
|
||||
namespace Carbon {
|
||||
namespace Carbon::Diagnostics {
|
||||
namespace {
|
||||
|
||||
using ::Carbon::Testing::IsSingleDiagnostic;
|
||||
@@ -20,21 +20,21 @@ using ::testing::InSequence;
|
||||
|
||||
CARBON_DIAGNOSTIC(TestDiagnostic, Error, "M{0}", int);
|
||||
|
||||
class FakeDiagnosticEmitter : public DiagnosticEmitter<int32_t> {
|
||||
class FakeEmitter : public Emitter<int32_t> {
|
||||
public:
|
||||
using DiagnosticEmitter::DiagnosticEmitter;
|
||||
using Emitter::Emitter;
|
||||
|
||||
protected:
|
||||
auto ConvertLoc(int32_t last_byte_offset, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> ConvertedLoc override {
|
||||
return {.loc = {}, .last_byte_offset = last_byte_offset};
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SortedDiagnosticEmitterTest, SortErrors) {
|
||||
TEST(SortedEmitterTest, SortErrors) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
SortingDiagnosticConsumer sorting_consumer(consumer);
|
||||
FakeDiagnosticEmitter emitter(&sorting_consumer);
|
||||
SortingConsumer sorting_consumer(consumer);
|
||||
FakeEmitter emitter(&sorting_consumer);
|
||||
|
||||
emitter.Emit(1, TestDiagnostic, 1);
|
||||
emitter.Emit(-1, TestDiagnostic, 2);
|
||||
@@ -45,25 +45,19 @@ TEST(SortedDiagnosticEmitterTest, SortErrors) {
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, _, _, "M2")));
|
||||
Kind::TestDiagnostic, Level::Error, _, _, "M2")));
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, _, _, "M3")));
|
||||
Kind::TestDiagnostic, Level::Error, _, _, "M3")));
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, _, _, "M1")));
|
||||
Kind::TestDiagnostic, Level::Error, _, _, "M1")));
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, _, _, "M5")));
|
||||
Kind::TestDiagnostic, Level::Error, _, _, "M5")));
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, _, _, "M6")));
|
||||
Kind::TestDiagnostic, Level::Error, _, _, "M6")));
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TestDiagnostic,
|
||||
DiagnosticLevel::Error, _, _, "M4")));
|
||||
Kind::TestDiagnostic, Level::Error, _, _, "M4")));
|
||||
sorting_consumer.Flush();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon
|
||||
} // namespace Carbon::Diagnostics
|
||||
|
||||
@@ -299,8 +299,8 @@ static auto PhaseToString(CompileOptions::Phase phase) -> std::string {
|
||||
}
|
||||
}
|
||||
|
||||
auto CompileSubcommand::ValidateOptions(NoLocDiagnosticEmitter& emitter) const
|
||||
-> bool {
|
||||
auto CompileSubcommand::ValidateOptions(
|
||||
Diagnostics::NoLocEmitter& emitter) const -> bool {
|
||||
CARBON_DIAGNOSTIC(
|
||||
CompilePhaseFlagConflict, Error,
|
||||
"requested dumping {0} but compile phase is limited to `{1}`",
|
||||
@@ -341,7 +341,7 @@ namespace {
|
||||
class CompilationUnit {
|
||||
public:
|
||||
explicit CompilationUnit(DriverEnv& driver_env, const CompileOptions& options,
|
||||
DiagnosticConsumer* consumer,
|
||||
Diagnostics::Consumer* consumer,
|
||||
llvm::StringRef input_filename);
|
||||
|
||||
// Loads source and lexes it. Returns true on success.
|
||||
@@ -411,8 +411,8 @@ class CompilationUnit {
|
||||
llvm::raw_pwrite_stream* vlog_stream_;
|
||||
|
||||
// Diagnostics are sent to consumer_, with optional sorting.
|
||||
std::optional<SortingDiagnosticConsumer> sorting_consumer_;
|
||||
DiagnosticConsumer* consumer_;
|
||||
std::optional<Diagnostics::SortingConsumer> sorting_consumer_;
|
||||
Diagnostics::Consumer* consumer_;
|
||||
|
||||
bool success_ = true;
|
||||
|
||||
@@ -436,7 +436,7 @@ class CompilationUnit {
|
||||
|
||||
CompilationUnit::CompilationUnit(DriverEnv& driver_env,
|
||||
const CompileOptions& options,
|
||||
DiagnosticConsumer* consumer,
|
||||
Diagnostics::Consumer* consumer,
|
||||
llvm::StringRef input_filename)
|
||||
: driver_env_(&driver_env),
|
||||
options_(options),
|
||||
@@ -445,7 +445,7 @@ CompilationUnit::CompilationUnit(DriverEnv& driver_env,
|
||||
if (vlog_stream_ != nullptr || options_.stream_errors) {
|
||||
consumer_ = consumer;
|
||||
} else {
|
||||
sorting_consumer_ = SortingDiagnosticConsumer(*consumer);
|
||||
sorting_consumer_ = Diagnostics::SortingConsumer(*consumer);
|
||||
consumer_ = &*sorting_consumer_;
|
||||
}
|
||||
if (options_.dump_mem_usage && IncludeInDumps()) {
|
||||
|
||||
@@ -77,7 +77,7 @@ class CompileSubcommand : public DriverSubcommand {
|
||||
// Does custom validation of the compile-subcommand options structure beyond
|
||||
// what the command line parsing library supports. Diagnoses and returns false
|
||||
// on failure.
|
||||
auto ValidateOptions(NoLocDiagnosticEmitter& emitter) const -> bool;
|
||||
auto ValidateOptions(Diagnostics::NoLocEmitter& emitter) const -> bool;
|
||||
|
||||
CompileOptions options_;
|
||||
};
|
||||
|
||||
@@ -56,10 +56,10 @@ struct DriverEnv {
|
||||
bool enable_leaking = false;
|
||||
|
||||
// A diagnostic consumer, to be able to connect output.
|
||||
StreamDiagnosticConsumer consumer;
|
||||
Diagnostics::StreamConsumer consumer;
|
||||
|
||||
// A diagnostic emitter that has no locations.
|
||||
NoLocDiagnosticEmitter emitter;
|
||||
Diagnostics::NoLocEmitter emitter;
|
||||
|
||||
// For CARBON_VLOG.
|
||||
llvm::raw_pwrite_stream* vlog_stream = nullptr;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Carbon::LanguageServer {
|
||||
// A consumer for turning diagnostics into a `textDocument/publishDiagnostics`
|
||||
// notification.
|
||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_publishDiagnostics
|
||||
class PublishDiagnosticConsumer : public DiagnosticConsumer {
|
||||
class PublishDiagnosticConsumer : public Diagnostics::Consumer {
|
||||
public:
|
||||
// Initializes params with the target file information.
|
||||
explicit PublishDiagnosticConsumer(Context* context,
|
||||
@@ -31,14 +31,14 @@ class PublishDiagnosticConsumer : public DiagnosticConsumer {
|
||||
: context_(context), params_{.uri = uri, .version = version} {}
|
||||
|
||||
// Turns a diagnostic into an LSP diagnostic.
|
||||
auto HandleDiagnostic(Diagnostic diagnostic) -> void override {
|
||||
auto HandleDiagnostic(Diagnostics::Diagnostic diagnostic) -> void override {
|
||||
const auto& message = diagnostic.messages[0];
|
||||
if (message.loc.filename != params_.uri.file()) {
|
||||
// `pushDiagnostic` requires diagnostics to be associated with a location
|
||||
// in the current file. Suppress diagnostics rooted in other files.
|
||||
// TODO: Consider if there's a better way to handle this.
|
||||
RawStringOstream stream;
|
||||
StreamDiagnosticConsumer consumer(&stream);
|
||||
Diagnostics::StreamConsumer consumer(&stream);
|
||||
consumer.HandleDiagnostic(diagnostic);
|
||||
|
||||
CARBON_DIAGNOSTIC(LanguageServerDiagnosticInWrongFile, Warning,
|
||||
@@ -68,7 +68,7 @@ class PublishDiagnosticConsumer : public DiagnosticConsumer {
|
||||
private:
|
||||
// Returns the LSP range for a diagnostic. Note that Carbon uses 1-based
|
||||
// numbers while LSP uses 0-based.
|
||||
auto GetRange(const DiagnosticLoc& loc) -> clang::clangd::Range {
|
||||
auto GetRange(const Diagnostics::Loc& loc) -> clang::clangd::Range {
|
||||
return {.start = {.line = loc.line_number - 1,
|
||||
.character = loc.column_number - 1},
|
||||
.end = {.line = loc.line_number,
|
||||
@@ -76,7 +76,7 @@ class PublishDiagnosticConsumer : public DiagnosticConsumer {
|
||||
}
|
||||
|
||||
// Converts a diagnostic level to an LSP severity.
|
||||
auto GetSeverity(DiagnosticLevel level) -> int {
|
||||
auto GetSeverity(Diagnostics::Level level) -> int {
|
||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticSeverity
|
||||
enum class DiagnosticSeverity {
|
||||
Error = 1,
|
||||
@@ -86,9 +86,9 @@ class PublishDiagnosticConsumer : public DiagnosticConsumer {
|
||||
};
|
||||
|
||||
switch (level) {
|
||||
case DiagnosticLevel::Error:
|
||||
case Diagnostics::Level::Error:
|
||||
return static_cast<int>(DiagnosticSeverity::Error);
|
||||
case DiagnosticLevel::Warning:
|
||||
case Diagnostics::Level::Warning:
|
||||
return static_cast<int>(DiagnosticSeverity::Warning);
|
||||
default:
|
||||
CARBON_FATAL("Unexpected diagnostic level: {0}", level);
|
||||
|
||||
@@ -52,7 +52,8 @@ class Context {
|
||||
};
|
||||
|
||||
// `vlog_stream` is optional; other parameters are required.
|
||||
explicit Context(llvm::raw_ostream* vlog_stream, DiagnosticConsumer* consumer,
|
||||
explicit Context(llvm::raw_ostream* vlog_stream,
|
||||
Diagnostics::Consumer* consumer,
|
||||
clang::clangd::LSPBinder::RawOutgoing* outgoing)
|
||||
: vlog_stream_(vlog_stream),
|
||||
file_emitter_(consumer),
|
||||
@@ -70,16 +71,18 @@ class Context {
|
||||
}
|
||||
|
||||
auto vlog_stream() -> llvm::raw_ostream* { return vlog_stream_; }
|
||||
auto file_emitter() -> FileDiagnosticEmitter& { return file_emitter_; }
|
||||
auto no_loc_emitter() -> NoLocDiagnosticEmitter& { return no_loc_emitter_; }
|
||||
auto file_emitter() -> Diagnostics::FileEmitter& { return file_emitter_; }
|
||||
auto no_loc_emitter() -> Diagnostics::NoLocEmitter& {
|
||||
return no_loc_emitter_;
|
||||
}
|
||||
|
||||
auto files() -> Map<std::string, File>& { return files_; }
|
||||
|
||||
private:
|
||||
// Diagnostic and output streams.
|
||||
llvm::raw_ostream* vlog_stream_;
|
||||
FileDiagnosticEmitter file_emitter_;
|
||||
NoLocDiagnosticEmitter no_loc_emitter_;
|
||||
Diagnostics::FileEmitter file_emitter_;
|
||||
Diagnostics::NoLocEmitter no_loc_emitter_;
|
||||
clang::clangd::LSPBinder::RawOutgoing* outgoing_;
|
||||
|
||||
// Content of files managed by the language client.
|
||||
|
||||
@@ -44,7 +44,7 @@ class Logger : public clang::clangd::Logger {
|
||||
|
||||
auto Run(FILE* input_stream, llvm::raw_ostream& output_stream,
|
||||
llvm::raw_ostream& error_stream, llvm::raw_ostream* vlog_stream,
|
||||
DiagnosticConsumer& consumer) -> bool {
|
||||
Diagnostics::Consumer& consumer) -> bool {
|
||||
// The language server internally uses diagnostics for logging issues, but the
|
||||
// clangd parts have their own logging system. We intercept that here.
|
||||
Logger logger(&error_stream, vlog_stream);
|
||||
@@ -65,7 +65,7 @@ auto Run(FILE* input_stream, llvm::raw_ostream& output_stream,
|
||||
RawStringOstream out;
|
||||
out << err;
|
||||
CARBON_DIAGNOSTIC(LanguageServerTransportError, Error, "{0}", std::string);
|
||||
NoLocDiagnosticEmitter emitter(&consumer);
|
||||
Diagnostics::NoLocEmitter emitter(&consumer);
|
||||
emitter.Emit(LanguageServerTransportError, out.TakeStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Carbon::LanguageServer {
|
||||
// This is thread-hostile because `clangd::LoggingSession` relies on a global.
|
||||
auto Run(FILE* input_stream, llvm::raw_ostream& output_stream,
|
||||
llvm::raw_ostream& error_stream, llvm::raw_ostream* vlog_stream,
|
||||
DiagnosticConsumer& consumer) -> bool;
|
||||
Diagnostics::Consumer& consumer) -> bool;
|
||||
|
||||
} // namespace Carbon::LanguageServer
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace Carbon::Lex {
|
||||
|
||||
auto CanLexInt(DiagnosticEmitter<const char*>& emitter, llvm::StringRef text)
|
||||
auto CanLexInt(Diagnostics::Emitter<const char*>& emitter, llvm::StringRef text)
|
||||
-> bool {
|
||||
// llvm::getAsInteger is used for parsing, but it's quadratic and visibly slow
|
||||
// on large integer values. This limit exists to avoid hitting those limits.
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Carbon::Lex {
|
||||
|
||||
// Should guard calls to getAsInteger due to performance issues with large
|
||||
// integers. Emits an error if the text cannot be lexed.
|
||||
auto CanLexInt(DiagnosticEmitter<const char*>& emitter, llvm::StringRef text)
|
||||
auto CanLexInt(Diagnostics::Emitter<const char*>& emitter, llvm::StringRef text)
|
||||
-> bool;
|
||||
|
||||
} // namespace Carbon::Lex
|
||||
|
||||
@@ -81,7 +81,7 @@ class [[clang::internal_linkage]] Lexer {
|
||||
};
|
||||
|
||||
Lexer(SharedValueStores& value_stores, SourceBuffer& source,
|
||||
DiagnosticConsumer& consumer)
|
||||
Diagnostics::Consumer& consumer)
|
||||
: buffer_(value_stores, source),
|
||||
consumer_(consumer),
|
||||
emitter_(&consumer_, &buffer_),
|
||||
@@ -220,7 +220,7 @@ class [[clang::internal_linkage]] Lexer {
|
||||
llvm::SmallVector<TokenIndex> open_groups_;
|
||||
bool has_mismatched_brackets_ = false;
|
||||
|
||||
ErrorTrackingDiagnosticConsumer consumer_;
|
||||
Diagnostics::ErrorTrackingConsumer consumer_;
|
||||
|
||||
TokenizedBuffer::SourcePointerDiagnosticEmitter emitter_;
|
||||
|
||||
@@ -1526,7 +1526,7 @@ class Lexer::ErrorRecoveryBuffer {
|
||||
};
|
||||
|
||||
// Issue an UnmatchedOpening diagnostic.
|
||||
static auto DiagnoseUnmatchedOpening(DiagnosticEmitter<TokenIndex>& emitter,
|
||||
static auto DiagnoseUnmatchedOpening(Diagnostics::Emitter<TokenIndex>& emitter,
|
||||
TokenIndex opening_token) -> void {
|
||||
CARBON_DIAGNOSTIC(UnmatchedOpening, Error,
|
||||
"opening symbol without a corresponding closing symbol");
|
||||
@@ -1610,7 +1610,7 @@ auto Lexer::DiagnoseAndFixMismatchedBrackets() -> void {
|
||||
}
|
||||
|
||||
auto Lex(SharedValueStores& value_stores, SourceBuffer& source,
|
||||
DiagnosticConsumer& consumer) -> TokenizedBuffer {
|
||||
Diagnostics::Consumer& consumer) -> TokenizedBuffer {
|
||||
return Lexer(value_stores, source, consumer).Lex();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ namespace Carbon::Lex {
|
||||
// which will refer into the source.
|
||||
auto Lex(SharedValueStores& value_stores,
|
||||
SourceBuffer& source [[clang::lifetimebound]],
|
||||
DiagnosticConsumer& consumer) -> TokenizedBuffer;
|
||||
Diagnostics::Consumer& consumer) -> TokenizedBuffer;
|
||||
|
||||
} // namespace Carbon::Lex
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ auto NumericLiteral::Lex(llvm::StringRef source_text,
|
||||
// either diagnosing or extracting its meaning.
|
||||
class NumericLiteral::Parser {
|
||||
public:
|
||||
Parser(DiagnosticEmitter<const char*>& emitter, NumericLiteral literal);
|
||||
Parser(Diagnostics::Emitter<const char*>& emitter, NumericLiteral literal);
|
||||
|
||||
auto IsInt() -> bool {
|
||||
return literal_.radix_point_ == static_cast<int>(literal_.text_.size());
|
||||
@@ -124,7 +124,7 @@ class NumericLiteral::Parser {
|
||||
auto CheckFractionalPart() -> bool;
|
||||
auto CheckExponentPart() -> bool;
|
||||
|
||||
DiagnosticEmitter<const char*>& emitter_;
|
||||
Diagnostics::Emitter<const char*>& emitter_;
|
||||
NumericLiteral literal_;
|
||||
|
||||
// The radix of the literal: 2, 10, or 16, for a prefix of '0b', no prefix,
|
||||
@@ -147,7 +147,7 @@ class NumericLiteral::Parser {
|
||||
bool exponent_is_negative_ = false;
|
||||
};
|
||||
|
||||
NumericLiteral::Parser::Parser(DiagnosticEmitter<const char*>& emitter,
|
||||
NumericLiteral::Parser::Parser(Diagnostics::Emitter<const char*>& emitter,
|
||||
NumericLiteral literal)
|
||||
: emitter_(emitter), literal_(literal) {
|
||||
int_part_ = literal.text_.substr(0, literal.radix_point_);
|
||||
@@ -292,7 +292,7 @@ auto NumericLiteral::Parser::CheckDigitSequence(llvm::StringRef text,
|
||||
InvalidDigit, Error,
|
||||
"invalid digit '{0}' in {1:=2:binary|=10:decimal|=16:hexadecimal} "
|
||||
"numeric literal",
|
||||
char, IntAsSelect);
|
||||
char, Diagnostics::IntAsSelect);
|
||||
emitter_.Emit(text.begin() + i, InvalidDigit, c, static_cast<int>(radix));
|
||||
return {.ok = false};
|
||||
}
|
||||
@@ -374,8 +374,8 @@ auto NumericLiteral::Parser::CheckExponentPart() -> bool {
|
||||
}
|
||||
|
||||
// Parse the token and compute its value.
|
||||
auto NumericLiteral::ComputeValue(DiagnosticEmitter<const char*>& emitter) const
|
||||
-> Value {
|
||||
auto NumericLiteral::ComputeValue(
|
||||
Diagnostics::Emitter<const char*>& emitter) const -> Value {
|
||||
Parser parser(emitter, *this);
|
||||
|
||||
if (!parser.Check()) {
|
||||
|
||||
@@ -47,7 +47,7 @@ class NumericLiteral {
|
||||
|
||||
// Compute the value of the token, if possible. Emit diagnostics to the given
|
||||
// emitter if the token is not valid.
|
||||
auto ComputeValue(DiagnosticEmitter<const char*>& emitter) const -> Value;
|
||||
auto ComputeValue(Diagnostics::Emitter<const char*>& emitter) const -> Value;
|
||||
|
||||
// Get the text corresponding to this literal.
|
||||
auto text() const -> llvm::StringRef { return text_; }
|
||||
|
||||
@@ -26,7 +26,7 @@ static void BM_Lex_Int(benchmark::State& state) {
|
||||
static void BM_ComputeValue_Float(benchmark::State& state) {
|
||||
auto val = NumericLiteral::Lex("0.000001", true);
|
||||
CARBON_CHECK(val);
|
||||
auto& emitter = NullDiagnosticEmitter<const char*>();
|
||||
auto& emitter = Diagnostics::NullEmitter<const char*>();
|
||||
for (auto _ : state) {
|
||||
val->ComputeValue(emitter);
|
||||
}
|
||||
@@ -34,7 +34,7 @@ static void BM_ComputeValue_Float(benchmark::State& state) {
|
||||
|
||||
static void BM_ComputeValue_Int(benchmark::State& state) {
|
||||
auto val = NumericLiteral::Lex("1_234_567_890", true);
|
||||
auto& emitter = NullDiagnosticEmitter<const char*>();
|
||||
auto& emitter = Diagnostics::NullEmitter<const char*>();
|
||||
CARBON_CHECK(val);
|
||||
for (auto _ : state) {
|
||||
val->ComputeValue(emitter);
|
||||
|
||||
@@ -21,7 +21,7 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
|
||||
}
|
||||
|
||||
volatile auto value =
|
||||
token->ComputeValue(NullDiagnosticEmitter<const char*>());
|
||||
token->ComputeValue(Diagnostics::NullEmitter<const char*>());
|
||||
(void)value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ using ::testing::VariantWith;
|
||||
|
||||
class NumericLiteralTest : public ::testing::Test {
|
||||
public:
|
||||
NumericLiteralTest() : error_tracker(ConsoleDiagnosticConsumer()) {}
|
||||
NumericLiteralTest() : error_tracker(Diagnostics::ConsoleConsumer()) {}
|
||||
|
||||
auto Lex(llvm::StringRef text, bool can_form_real_literal) -> NumericLiteral {
|
||||
std::optional<NumericLiteral> result =
|
||||
@@ -41,7 +41,7 @@ class NumericLiteralTest : public ::testing::Test {
|
||||
return Lex(text, can_form_real_literal).ComputeValue(emitter);
|
||||
}
|
||||
|
||||
ErrorTrackingDiagnosticConsumer error_tracker;
|
||||
Diagnostics::ErrorTrackingConsumer error_tracker;
|
||||
};
|
||||
|
||||
// Matcher for signed llvm::APInt.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace Carbon::Lex {
|
||||
|
||||
using LexerDiagnosticEmitter = DiagnosticEmitter<const char*>;
|
||||
using LexerDiagnosticEmitter = Diagnostics::Emitter<const char*>;
|
||||
|
||||
static constexpr char MultiLineIndicator[] = R"(''')";
|
||||
static constexpr char DoubleQuotedMultiLineIndicator[] = R"(""")";
|
||||
|
||||
@@ -29,7 +29,7 @@ class StringLiteral {
|
||||
// deal with, this can return the content directly. Otherwise, the allocator
|
||||
// will be used for the StringRef.
|
||||
auto ComputeValue(llvm::BumpPtrAllocator& allocator,
|
||||
DiagnosticEmitter<const char*>& emitter) const
|
||||
Diagnostics::Emitter<const char*>& emitter) const
|
||||
-> llvm::StringRef;
|
||||
|
||||
// Get the text corresponding to this literal.
|
||||
|
||||
@@ -94,8 +94,8 @@ static void BM_SimpleStringValue(benchmark::State& state, int size,
|
||||
}
|
||||
x.append(terminator);
|
||||
for (auto _ : state) {
|
||||
StringLiteral::Lex(x)->ComputeValue(allocator,
|
||||
NullDiagnosticEmitter<const char*>());
|
||||
StringLiteral::Lex(x)->ComputeValue(
|
||||
allocator, Diagnostics::NullEmitter<const char*>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
|
||||
|
||||
llvm::BumpPtrAllocator allocator;
|
||||
volatile auto value =
|
||||
token->ComputeValue(allocator, NullDiagnosticEmitter<const char*>());
|
||||
token->ComputeValue(allocator, Diagnostics::NullEmitter<const char*>());
|
||||
(void)value;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace {
|
||||
|
||||
class StringLiteralTest : public ::testing::Test {
|
||||
public:
|
||||
StringLiteralTest() : error_tracker_(ConsoleDiagnosticConsumer()) {}
|
||||
StringLiteralTest() : error_tracker_(Diagnostics::ConsoleConsumer()) {}
|
||||
|
||||
auto Lex(llvm::StringRef text) -> StringLiteral {
|
||||
std::optional<StringLiteral> result = StringLiteral::Lex(text);
|
||||
@@ -32,7 +32,7 @@ class StringLiteralTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
llvm::BumpPtrAllocator allocator_;
|
||||
ErrorTrackingDiagnosticConsumer error_tracker_;
|
||||
Diagnostics::ErrorTrackingConsumer error_tracker_;
|
||||
};
|
||||
|
||||
TEST_F(StringLiteralTest, StringLiteralBounds) {
|
||||
|
||||
@@ -17,18 +17,18 @@ namespace Carbon::Testing {
|
||||
|
||||
// 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 SingleTokenDiagnosticEmitter : public DiagnosticEmitter<const char*> {
|
||||
class SingleTokenDiagnosticEmitter : public Diagnostics::Emitter<const char*> {
|
||||
public:
|
||||
// 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 SingleTokenDiagnosticEmitter(DiagnosticConsumer* consumer,
|
||||
explicit SingleTokenDiagnosticEmitter(Diagnostics::Consumer* consumer,
|
||||
llvm::StringRef token)
|
||||
: DiagnosticEmitter(consumer), token_(token) {}
|
||||
: Emitter(consumer), token_(token) {}
|
||||
|
||||
protected:
|
||||
// Implements `DiagnosticConverter::ConvertLoc`.
|
||||
auto ConvertLoc(const char* pos, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> Diagnostics::ConvertedLoc override {
|
||||
CARBON_CHECK(StringRefContainsPointer(token_, pos),
|
||||
"invalid diagnostic location");
|
||||
llvm::StringRef prefix = token_.take_front(pos - token_.begin());
|
||||
|
||||
@@ -378,7 +378,7 @@ auto TokenizedBuffer::CollectMemUsage(MemUsage& mem_usage,
|
||||
}
|
||||
|
||||
auto TokenizedBuffer::SourcePointerToDiagnosticLoc(const char* loc) const
|
||||
-> ConvertedDiagnosticLoc {
|
||||
-> Diagnostics::ConvertedLoc {
|
||||
CARBON_CHECK(StringRefContainsPointer(source_->text(), loc),
|
||||
"location not within buffer");
|
||||
int32_t offset = loc - source_->text().begin();
|
||||
@@ -416,7 +416,7 @@ auto TokenizedBuffer::SourcePointerToDiagnosticLoc(const char* loc) const
|
||||
}
|
||||
|
||||
auto TokenizedBuffer::TokenToDiagnosticLoc(TokenIndex token) const
|
||||
-> ConvertedDiagnosticLoc {
|
||||
-> Diagnostics::ConvertedLoc {
|
||||
// Map the token location into a position within the source buffer.
|
||||
const char* token_start =
|
||||
source_->text().begin() + GetTokenInfo(token).byte_offset();
|
||||
|
||||
@@ -177,7 +177,8 @@ class TokenizedBuffer : public Printable<TokenizedBuffer> {
|
||||
-> void;
|
||||
|
||||
// Converts a token to a diagnostic location.
|
||||
auto TokenToDiagnosticLoc(TokenIndex token) const -> ConvertedDiagnosticLoc;
|
||||
auto TokenToDiagnosticLoc(TokenIndex token) const
|
||||
-> Diagnostics::ConvertedLoc;
|
||||
|
||||
// Returns true if the buffer has errors that were detected at lexing time.
|
||||
auto has_errors() const -> bool { return has_errors_; }
|
||||
@@ -207,15 +208,16 @@ class TokenizedBuffer : public Printable<TokenizedBuffer> {
|
||||
private:
|
||||
friend class Lexer;
|
||||
|
||||
class SourcePointerDiagnosticEmitter : public DiagnosticEmitter<const char*> {
|
||||
class SourcePointerDiagnosticEmitter
|
||||
: public Diagnostics::Emitter<const char*> {
|
||||
public:
|
||||
explicit SourcePointerDiagnosticEmitter(DiagnosticConsumer* consumer,
|
||||
explicit SourcePointerDiagnosticEmitter(Diagnostics::Consumer* consumer,
|
||||
const TokenizedBuffer* tokens)
|
||||
: DiagnosticEmitter(consumer), tokens_(tokens) {}
|
||||
: Emitter(consumer), tokens_(tokens) {}
|
||||
|
||||
protected:
|
||||
auto ConvertLoc(const char* loc, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> Diagnostics::ConvertedLoc override {
|
||||
return tokens_->SourcePointerToDiagnosticLoc(loc);
|
||||
}
|
||||
|
||||
@@ -223,15 +225,15 @@ class TokenizedBuffer : public Printable<TokenizedBuffer> {
|
||||
const TokenizedBuffer* tokens_;
|
||||
};
|
||||
|
||||
class TokenDiagnosticEmitter : public DiagnosticEmitter<TokenIndex> {
|
||||
class TokenDiagnosticEmitter : public Diagnostics::Emitter<TokenIndex> {
|
||||
public:
|
||||
explicit TokenDiagnosticEmitter(DiagnosticConsumer* consumer,
|
||||
explicit TokenDiagnosticEmitter(Diagnostics::Consumer* consumer,
|
||||
const TokenizedBuffer* tokens)
|
||||
: DiagnosticEmitter(consumer), tokens_(tokens) {}
|
||||
: Emitter(consumer), tokens_(tokens) {}
|
||||
|
||||
protected:
|
||||
auto ConvertLoc(TokenIndex token, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> Diagnostics::ConvertedLoc override {
|
||||
return tokens_->TokenToDiagnosticLoc(token);
|
||||
}
|
||||
|
||||
@@ -241,7 +243,7 @@ class TokenizedBuffer : public Printable<TokenizedBuffer> {
|
||||
|
||||
// Converts a pointer into the source to a diagnostic location.
|
||||
auto SourcePointerToDiagnosticLoc(const char* loc) const
|
||||
-> ConvertedDiagnosticLoc;
|
||||
-> Diagnostics::ConvertedLoc;
|
||||
|
||||
// Specifies minimum widths to use when printing a token's fields via
|
||||
// `printToken`.
|
||||
|
||||
@@ -214,13 +214,13 @@ class LexerBenchHelper {
|
||||
: source_(MakeSourceBuffer(text)) {}
|
||||
|
||||
auto Lex() -> TokenizedBuffer {
|
||||
DiagnosticConsumer& consumer = NullDiagnosticConsumer();
|
||||
Diagnostics::Consumer& consumer = Diagnostics::NullConsumer();
|
||||
return Lex::Lex(value_stores_, source_, consumer);
|
||||
}
|
||||
|
||||
auto DiagnoseErrors() -> std::string {
|
||||
RawStringOstream result;
|
||||
StreamDiagnosticConsumer consumer(&result);
|
||||
Diagnostics::StreamConsumer consumer(&result);
|
||||
auto buffer = Lex::Lex(value_stores_, source_, consumer);
|
||||
consumer.Flush();
|
||||
CARBON_CHECK(buffer.has_errors(),
|
||||
@@ -234,8 +234,8 @@ class LexerBenchHelper {
|
||||
auto MakeSourceBuffer(llvm::StringRef text) -> SourceBuffer {
|
||||
CARBON_CHECK(fs_.addFile(filename_, /*ModificationTime=*/0,
|
||||
llvm::MemoryBuffer::getMemBuffer(text)));
|
||||
return std::move(*SourceBuffer::MakeFromFile(fs_, filename_,
|
||||
ConsoleDiagnosticConsumer()));
|
||||
return std::move(*SourceBuffer::MakeFromFile(
|
||||
fs_, filename_, Diagnostics::ConsoleConsumer()));
|
||||
}
|
||||
|
||||
SharedValueStores value_stores_;
|
||||
|
||||
@@ -32,10 +32,10 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
|
||||
llvm::MemoryBuffer::getMemBuffer(data_ref, /*BufferName=*/TestFileName,
|
||||
/*RequiresNullTerminator=*/false)));
|
||||
auto source =
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, NullDiagnosticConsumer());
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, Diagnostics::NullConsumer());
|
||||
|
||||
SharedValueStores value_stores;
|
||||
auto buffer = Lex::Lex(value_stores, *source, NullDiagnosticConsumer());
|
||||
auto buffer = Lex::Lex(value_stores, *source, Diagnostics::NullConsumer());
|
||||
if (buffer.has_errors()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1028,8 +1028,8 @@ TEST_F(LexerTest, TypeLiteralTooManyDigits) {
|
||||
// We increase the number of digits until the first one that is to large.
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TooManyTypeBitWidthDigits,
|
||||
DiagnosticLevel::Error, 1, 2, _)));
|
||||
Diagnostics::Kind::TooManyTypeBitWidthDigits,
|
||||
Diagnostics::Level::Error, 1, 2, _)));
|
||||
std::string code = "i";
|
||||
// A 128-bit APInt should be plenty large, but if needed in the future it can
|
||||
// be widened without issue.
|
||||
@@ -1061,8 +1061,8 @@ TEST_F(LexerTest, TypeLiteralTooManyDigits) {
|
||||
// crashing or hanging, and show the correct number.
|
||||
constexpr int Count = 10000;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TooManyTypeBitWidthDigits,
|
||||
DiagnosticLevel::Error, 1, 2,
|
||||
Diagnostics::Kind::TooManyTypeBitWidthDigits,
|
||||
Diagnostics::Level::Error, 1, 2,
|
||||
HasSubstr(llvm::formatv(" {0} ", Count)))));
|
||||
code = "i";
|
||||
code.append(Count, '9');
|
||||
@@ -1083,72 +1083,75 @@ TEST_F(LexerTest, DiagnosticTrailingComment) {
|
||||
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::TrailingComment,
|
||||
DiagnosticLevel::Error, 3, 19, _)));
|
||||
Diagnostics::Kind::TrailingComment,
|
||||
Diagnostics::Level::Error, 3, 19, _)));
|
||||
compile_helper_.GetTokenizedBuffer(testcase, &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticWhitespace) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::NoWhitespaceAfterCommentIntroducer,
|
||||
DiagnosticLevel::Error, 1, 3, _)));
|
||||
EXPECT_CALL(consumer,
|
||||
HandleDiagnostic(IsSingleDiagnostic(
|
||||
Diagnostics::Kind::NoWhitespaceAfterCommentIntroducer,
|
||||
Diagnostics::Level::Error, 1, 3, _)));
|
||||
compile_helper_.GetTokenizedBuffer("//no space after comment", &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticUnrecognizedEscape) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::UnknownEscapeSequence,
|
||||
DiagnosticLevel::Error, 1, 8, HasSubstr("`b`"))));
|
||||
EXPECT_CALL(consumer,
|
||||
HandleDiagnostic(IsSingleDiagnostic(
|
||||
Diagnostics::Kind::UnknownEscapeSequence,
|
||||
Diagnostics::Level::Error, 1, 8, HasSubstr("`b`"))));
|
||||
compile_helper_.GetTokenizedBuffer(R"("hello\bworld")", &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticBadHex) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::HexadecimalEscapeMissingDigits,
|
||||
DiagnosticLevel::Error, 1, 9, _)));
|
||||
Diagnostics::Kind::HexadecimalEscapeMissingDigits,
|
||||
Diagnostics::Level::Error, 1, 9, _)));
|
||||
compile_helper_.GetTokenizedBuffer(R"("hello\xabworld")", &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticInvalidDigit) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::InvalidDigit,
|
||||
DiagnosticLevel::Error, 1, 6, HasSubstr("'a'"))));
|
||||
EXPECT_CALL(consumer,
|
||||
HandleDiagnostic(IsSingleDiagnostic(
|
||||
Diagnostics::Kind::InvalidDigit, Diagnostics::Level::Error, 1,
|
||||
6, HasSubstr("'a'"))));
|
||||
compile_helper_.GetTokenizedBuffer("0x123abc", &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticCR) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::UnsupportedCrLineEnding,
|
||||
DiagnosticLevel::Error, 1, 1, _)));
|
||||
Diagnostics::Kind::UnsupportedCrLineEnding,
|
||||
Diagnostics::Level::Error, 1, 1, _)));
|
||||
compile_helper_.GetTokenizedBuffer("\r", &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticLfCr) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::UnsupportedLfCrLineEnding,
|
||||
DiagnosticLevel::Error, 2, 1, _)));
|
||||
Diagnostics::Kind::UnsupportedLfCrLineEnding,
|
||||
Diagnostics::Level::Error, 2, 1, _)));
|
||||
compile_helper_.GetTokenizedBuffer("\n\r", &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticMissingTerminator) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::UnterminatedString,
|
||||
DiagnosticLevel::Error, 1, 1, _)));
|
||||
Diagnostics::Kind::UnterminatedString,
|
||||
Diagnostics::Level::Error, 1, 1, _)));
|
||||
compile_helper_.GetTokenizedBuffer(R"(#" ")", &consumer);
|
||||
}
|
||||
|
||||
TEST_F(LexerTest, DiagnosticUnrecognizedChar) {
|
||||
Testing::MockDiagnosticConsumer consumer;
|
||||
EXPECT_CALL(consumer, HandleDiagnostic(IsSingleDiagnostic(
|
||||
DiagnosticKind::UnrecognizedCharacters,
|
||||
DiagnosticLevel::Error, 1, 1, _)));
|
||||
Diagnostics::Kind::UnrecognizedCharacters,
|
||||
Diagnostics::Level::Error, 1, 1, _)));
|
||||
compile_helper_.GetTokenizedBuffer("\b", &consumer);
|
||||
}
|
||||
|
||||
@@ -1161,9 +1164,9 @@ TEST_F(LexerTest, DiagnosticFileTooLarge) {
|
||||
input += "{}\n";
|
||||
}
|
||||
EXPECT_CALL(consumer,
|
||||
HandleDiagnostic(IsSingleDiagnostic(DiagnosticKind::TooManyTokens,
|
||||
DiagnosticLevel::Error,
|
||||
TokenIndex::Max / 2, 1, _)));
|
||||
HandleDiagnostic(IsSingleDiagnostic(
|
||||
Diagnostics::Kind::TooManyTokens, Diagnostics::Level::Error,
|
||||
TokenIndex::Max / 2, 1, _)));
|
||||
compile_helper_.GetTokenizedBuffer(input, &consumer);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
namespace Carbon::Parse {
|
||||
|
||||
Context::Context(Tree* tree, Lex::TokenizedBuffer* tokens,
|
||||
DiagnosticConsumer* consumer, llvm::raw_ostream* vlog_stream)
|
||||
Diagnostics::Consumer* consumer,
|
||||
llvm::raw_ostream* vlog_stream)
|
||||
: tree_(tree),
|
||||
tokens_(tokens),
|
||||
err_tracker_(*consumer),
|
||||
@@ -283,8 +284,8 @@ auto Context::DiagnoseOperatorFixity(OperatorFixity fixity) -> void {
|
||||
CARBON_DIAGNOSTIC(BinaryOperatorRequiresWhitespace, Error,
|
||||
"whitespace missing {0:=-1:before|=0:around|=1:after} "
|
||||
"binary operator",
|
||||
IntAsSelect);
|
||||
IntAsSelect pos(0);
|
||||
Diagnostics::IntAsSelect);
|
||||
Diagnostics::IntAsSelect pos(0);
|
||||
if (tokens().HasLeadingWhitespace(*position_)) {
|
||||
pos.value = 1;
|
||||
} else if (tokens().HasTrailingWhitespace(*position_)) {
|
||||
@@ -302,14 +303,14 @@ auto Context::DiagnoseOperatorFixity(OperatorFixity fixity) -> void {
|
||||
CARBON_DIAGNOSTIC(
|
||||
UnaryOperatorHasWhitespace, Error,
|
||||
"whitespace is not allowed {0:after|before} this unary operator",
|
||||
BoolAsSelect);
|
||||
Diagnostics::BoolAsSelect);
|
||||
emitter_.Emit(*position_, UnaryOperatorHasWhitespace, prefix);
|
||||
} else if (IsLexicallyValidInfixOperator()) {
|
||||
// Pre/postfix operators must not satisfy the infix operator rules.
|
||||
CARBON_DIAGNOSTIC(
|
||||
UnaryOperatorRequiresWhitespace, Error,
|
||||
"whitespace is required {0:before|after} this unary operator",
|
||||
BoolAsSelect);
|
||||
Diagnostics::BoolAsSelect);
|
||||
emitter_.Emit(*position_, UnaryOperatorRequiresWhitespace, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,16 +35,16 @@ enum class Lookahead : int32_t {
|
||||
class Context {
|
||||
public:
|
||||
// A token-based emitter for use during parse.
|
||||
class Emitter : public DiagnosticEmitter<Lex::TokenIndex> {
|
||||
class TokenEmitter : public Diagnostics::Emitter<Lex::TokenIndex> {
|
||||
public:
|
||||
explicit Emitter(DiagnosticConsumer* consumer, Context* context)
|
||||
: DiagnosticEmitter(consumer), context_(context) {}
|
||||
explicit TokenEmitter(Diagnostics::Consumer* consumer, Context* context)
|
||||
: Emitter(consumer), context_(context) {}
|
||||
|
||||
protected:
|
||||
// Applies the `position_` to the `last_byte_offset` returned by
|
||||
// `TokenToDiagnosticLoc`.
|
||||
auto ConvertLoc(Lex::TokenIndex token, ContextFnT /*context_fn*/) const
|
||||
-> ConvertedDiagnosticLoc override {
|
||||
-> Diagnostics::ConvertedLoc override {
|
||||
auto converted = context_->tokens().TokenToDiagnosticLoc(token);
|
||||
converted.last_byte_offset =
|
||||
std::max(converted.last_byte_offset,
|
||||
@@ -122,7 +122,7 @@ class Context {
|
||||
"StateStackEntry has unexpected size!");
|
||||
|
||||
explicit Context(Tree* tree, Lex::TokenizedBuffer* tokens,
|
||||
DiagnosticConsumer* consumer,
|
||||
Diagnostics::Consumer* consumer,
|
||||
llvm::raw_ostream* vlog_stream);
|
||||
|
||||
// Adds a node to the parse tree that has no children (a leaf).
|
||||
@@ -407,7 +407,7 @@ class Context {
|
||||
|
||||
auto has_errors() const -> bool { return err_tracker_.seen_error(); }
|
||||
|
||||
auto emitter() -> Emitter& { return emitter_; }
|
||||
auto emitter() -> TokenEmitter& { return emitter_; }
|
||||
|
||||
auto position() -> Lex::TokenIterator& { return position_; }
|
||||
auto position() const -> Lex::TokenIterator { return position_; }
|
||||
@@ -440,8 +440,8 @@ class Context {
|
||||
Tree* tree_;
|
||||
Lex::TokenizedBuffer* tokens_;
|
||||
|
||||
ErrorTrackingDiagnosticConsumer err_tracker_;
|
||||
Emitter emitter_;
|
||||
Diagnostics::ErrorTrackingConsumer err_tracker_;
|
||||
TokenEmitter emitter_;
|
||||
|
||||
// Whether to print verbose output.
|
||||
llvm::raw_ostream* vlog_stream_;
|
||||
|
||||
@@ -25,7 +25,7 @@ auto HandleBindingPattern(Context& context) -> void {
|
||||
if (!state.has_error) {
|
||||
CARBON_DIAGNOSTIC(ExpectedBindingPattern, Error,
|
||||
"expected {0:name|`:` or `:!`} in binding pattern",
|
||||
BoolAsSelect);
|
||||
Diagnostics::BoolAsSelect);
|
||||
context.emitter().Emit(*context.position(), ExpectedBindingPattern,
|
||||
expected_name);
|
||||
state.has_error = true;
|
||||
|
||||
@@ -23,7 +23,7 @@ auto HandleBraceExpr(Context& context) -> void {
|
||||
static auto HandleBraceExprParamError(Context& context,
|
||||
Context::StateStackEntry state,
|
||||
State param_finish_state) -> void {
|
||||
IntAsSelect mode(0);
|
||||
Diagnostics::IntAsSelect mode(0);
|
||||
switch (param_finish_state) {
|
||||
case State::BraceExprParamFinishAsType:
|
||||
mode.value = 0;
|
||||
@@ -41,7 +41,7 @@ static auto HandleBraceExprParamError(Context& context,
|
||||
ExpectedStructLiteralField, Error,
|
||||
"expected {0:=0:`.field: field_type`|"
|
||||
"=1:`.field = value`|=2:`.field: field_type` or `.field = value`}",
|
||||
IntAsSelect);
|
||||
Diagnostics::IntAsSelect);
|
||||
context.emitter().Emit(*context.position(), ExpectedStructLiteralField, mode);
|
||||
|
||||
state.has_error = true;
|
||||
|
||||
@@ -38,7 +38,8 @@ static auto HandlePeriodOrArrow(Context& context, NodeKind node_kind,
|
||||
return;
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPeriodOrArrow, Error,
|
||||
"expected identifier after `{0:->|.}`", BoolAsSelect);
|
||||
"expected identifier after `{0:->|.}`",
|
||||
Diagnostics::BoolAsSelect);
|
||||
context.emitter().Emit(*context.position(),
|
||||
ExpectedIdentifierAfterPeriodOrArrow, is_arrow);
|
||||
// If we see a keyword, assume it was intended to be a name.
|
||||
|
||||
@@ -17,7 +17,7 @@ auto HandleInvalid(Context& context) -> void {
|
||||
context.PopState());
|
||||
}
|
||||
|
||||
auto Parse(Lex::TokenizedBuffer& tokens, DiagnosticConsumer& consumer,
|
||||
auto Parse(Lex::TokenizedBuffer& tokens, Diagnostics::Consumer& consumer,
|
||||
llvm::raw_ostream* vlog_stream) -> Tree {
|
||||
// Delegate to the parser.
|
||||
Tree tree(tokens);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Carbon::Parse {
|
||||
// Parses the token buffer into a `Tree`.
|
||||
//
|
||||
// This is the factory function which is used to build parse trees.
|
||||
auto Parse(Lex::TokenizedBuffer& tokens, DiagnosticConsumer& consumer,
|
||||
auto Parse(Lex::TokenizedBuffer& tokens, Diagnostics::Consumer& consumer,
|
||||
llvm::raw_ostream* vlog_stream) -> Tree;
|
||||
|
||||
} // namespace Carbon::Parse
|
||||
|
||||
@@ -29,18 +29,18 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
|
||||
llvm::MemoryBuffer::getMemBuffer(data_ref, /*BufferName=*/TestFileName,
|
||||
/*RequiresNullTerminator=*/false)));
|
||||
auto source =
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, NullDiagnosticConsumer());
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, Diagnostics::NullConsumer());
|
||||
|
||||
// Lex the input.
|
||||
SharedValueStores value_stores;
|
||||
auto tokens = Lex::Lex(value_stores, *source, NullDiagnosticConsumer());
|
||||
auto tokens = Lex::Lex(value_stores, *source, Diagnostics::NullConsumer());
|
||||
if (tokens.has_errors()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Now parse it into a tree. Note that parsing will (when asserts are enabled)
|
||||
// walk the entire tree to verify it so we don't have to do that here.
|
||||
Parse::Parse(tokens, NullDiagnosticConsumer(), /*vlog_stream=*/nullptr);
|
||||
Parse::Parse(tokens, Diagnostics::NullConsumer(), /*vlog_stream=*/nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ auto TreeAndSubtrees::GetSubtreeTokenRange(NodeId node_id) const -> TokenRange {
|
||||
}
|
||||
|
||||
auto TreeAndSubtrees::NodeToDiagnosticLoc(NodeId node_id, bool token_only) const
|
||||
-> ConvertedDiagnosticLoc {
|
||||
-> Diagnostics::ConvertedLoc {
|
||||
// Support the invalid token as a way to emit only the filename, when there
|
||||
// is no line association.
|
||||
if (!node_id.has_value()) {
|
||||
|
||||
@@ -120,7 +120,7 @@ class TreeAndSubtrees {
|
||||
// Converts the node to a diagnostic location, covering either the full
|
||||
// subtree or only the token.
|
||||
auto NodeToDiagnosticLoc(NodeId node_id, bool token_only) const
|
||||
-> ConvertedDiagnosticLoc;
|
||||
-> Diagnostics::ConvertedLoc;
|
||||
|
||||
// Returns an iterable range over the parse tree node and all of its
|
||||
// descendants in depth-first postorder.
|
||||
|
||||
@@ -479,7 +479,7 @@ struct NameId : public IdBase<NameId> {
|
||||
static constexpr llvm::StringLiteral Label = "name";
|
||||
|
||||
// names().GetFormatted() is used for diagnostics.
|
||||
using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
// An enum of special names.
|
||||
enum class SpecialNameId : uint8_t {
|
||||
@@ -708,7 +708,7 @@ struct TypeId : public IdBase<TypeId> {
|
||||
// `StringifyTypeExpr` is used for diagnostics. However, where possible, an
|
||||
// `InstId` describing how the type was written should be preferred, using
|
||||
// `InstIdAsType` or `TypeOfInstId` as the diagnostic argument type.
|
||||
using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
using IdBase::IdBase;
|
||||
|
||||
@@ -755,7 +755,7 @@ struct ElementIndex : public IndexBase<ElementIndex> {
|
||||
// The ID of a library name. This is either a string literal or `default`.
|
||||
struct LibraryNameId : public IdBase<LibraryNameId> {
|
||||
static constexpr llvm::StringLiteral Label = "library_name";
|
||||
using DiagnosticType = DiagnosticTypeInfo<std::string>;
|
||||
using DiagnosticType = Diagnostics::TypeInfo<std::string>;
|
||||
|
||||
// The name of `default`.
|
||||
static const LibraryNameId Default;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
auto SourceBuffer::MakeFromStdin(DiagnosticConsumer& consumer)
|
||||
auto SourceBuffer::MakeFromStdin(Diagnostics::Consumer& consumer)
|
||||
-> std::optional<SourceBuffer> {
|
||||
return MakeFromMemoryBuffer(llvm::MemoryBuffer::getSTDIN(), "<stdin>",
|
||||
/*is_regular_file=*/false, consumer);
|
||||
@@ -19,9 +19,9 @@ auto SourceBuffer::MakeFromStdin(DiagnosticConsumer& consumer)
|
||||
|
||||
auto SourceBuffer::MakeFromFile(llvm::vfs::FileSystem& fs,
|
||||
llvm::StringRef filename,
|
||||
DiagnosticConsumer& consumer)
|
||||
Diagnostics::Consumer& consumer)
|
||||
-> std::optional<SourceBuffer> {
|
||||
FileDiagnosticEmitter emitter(&consumer);
|
||||
Diagnostics::FileEmitter emitter(&consumer);
|
||||
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> file =
|
||||
fs.openFileForRead(filename);
|
||||
@@ -53,7 +53,7 @@ auto SourceBuffer::MakeFromFile(llvm::vfs::FileSystem& fs,
|
||||
|
||||
auto SourceBuffer::MakeFromStringCopy(llvm::StringRef filename,
|
||||
llvm::StringRef text,
|
||||
DiagnosticConsumer& consumer)
|
||||
Diagnostics::Consumer& consumer)
|
||||
-> std::optional<SourceBuffer> {
|
||||
return MakeFromMemoryBuffer(
|
||||
llvm::MemoryBuffer::getMemBufferCopy(text, filename), filename,
|
||||
@@ -63,8 +63,8 @@ auto SourceBuffer::MakeFromStringCopy(llvm::StringRef filename,
|
||||
auto SourceBuffer::MakeFromMemoryBuffer(
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer,
|
||||
llvm::StringRef filename, bool is_regular_file,
|
||||
DiagnosticConsumer& consumer) -> std::optional<SourceBuffer> {
|
||||
FileDiagnosticEmitter emitter(&consumer);
|
||||
Diagnostics::Consumer& consumer) -> std::optional<SourceBuffer> {
|
||||
Diagnostics::FileEmitter emitter(&consumer);
|
||||
|
||||
if (buffer.getError()) {
|
||||
CARBON_DIAGNOSTIC(ErrorReadingFile, Error, "error reading file: {0}",
|
||||
|
||||
@@ -36,19 +36,19 @@ class SourceBuffer {
|
||||
public:
|
||||
// Opens and reads the contents of stdin. Returns a SourceBuffer on success.
|
||||
// Prints an error and returns nullopt on failure.
|
||||
static auto MakeFromStdin(DiagnosticConsumer& consumer)
|
||||
static auto MakeFromStdin(Diagnostics::Consumer& consumer)
|
||||
-> std::optional<SourceBuffer>;
|
||||
|
||||
// Opens the requested file. Returns a SourceBuffer on success. Prints an
|
||||
// error and returns nullopt on failure.
|
||||
static auto MakeFromFile(llvm::vfs::FileSystem& fs, llvm::StringRef filename,
|
||||
DiagnosticConsumer& consumer)
|
||||
Diagnostics::Consumer& consumer)
|
||||
-> std::optional<SourceBuffer>;
|
||||
|
||||
// Handles conditional use of stdin based on the filename being "-".
|
||||
static auto MakeFromFileOrStdin(llvm::vfs::FileSystem& fs,
|
||||
llvm::StringRef filename,
|
||||
DiagnosticConsumer& consumer)
|
||||
Diagnostics::Consumer& consumer)
|
||||
-> std::optional<SourceBuffer> {
|
||||
if (filename == "-") {
|
||||
return MakeFromStdin(consumer);
|
||||
@@ -60,7 +60,7 @@ class SourceBuffer {
|
||||
// Returns a source buffer with the provided text content. Copies `filename`
|
||||
// and `text` to take ownership.
|
||||
static auto MakeFromStringCopy(llvm::StringRef filename, llvm::StringRef text,
|
||||
DiagnosticConsumer& consumer)
|
||||
Diagnostics::Consumer& consumer)
|
||||
-> std::optional<SourceBuffer>;
|
||||
|
||||
// Use one of the factory functions above to create a source buffer.
|
||||
@@ -80,7 +80,7 @@ class SourceBuffer {
|
||||
static auto MakeFromMemoryBuffer(
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer,
|
||||
llvm::StringRef filename, bool is_regular_file,
|
||||
DiagnosticConsumer& consumer) -> std::optional<SourceBuffer>;
|
||||
Diagnostics::Consumer& consumer) -> std::optional<SourceBuffer>;
|
||||
|
||||
explicit SourceBuffer(std::string filename,
|
||||
std::unique_ptr<llvm::MemoryBuffer> text,
|
||||
|
||||
@@ -17,8 +17,8 @@ static constexpr llvm::StringLiteral TestFileName = "test.carbon";
|
||||
|
||||
TEST(SourceBufferTest, MissingFile) {
|
||||
llvm::vfs::InMemoryFileSystem fs;
|
||||
auto buffer =
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, ConsoleDiagnosticConsumer());
|
||||
auto buffer = SourceBuffer::MakeFromFile(fs, TestFileName,
|
||||
Diagnostics::ConsoleConsumer());
|
||||
EXPECT_FALSE(buffer);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ TEST(SourceBufferTest, SimpleFile) {
|
||||
CARBON_CHECK(fs.addFile(TestFileName, /*ModificationTime=*/0,
|
||||
llvm::MemoryBuffer::getMemBuffer("Hello World")));
|
||||
|
||||
auto buffer =
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, ConsoleDiagnosticConsumer());
|
||||
auto buffer = SourceBuffer::MakeFromFile(fs, TestFileName,
|
||||
Diagnostics::ConsoleConsumer());
|
||||
ASSERT_TRUE(buffer);
|
||||
|
||||
EXPECT_EQ(TestFileName, buffer->filename());
|
||||
@@ -44,8 +44,8 @@ TEST(SourceBufferTest, NoNull) {
|
||||
/*BufferName=*/"",
|
||||
/*RequiresNullTerminator=*/false)));
|
||||
|
||||
auto buffer =
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, ConsoleDiagnosticConsumer());
|
||||
auto buffer = SourceBuffer::MakeFromFile(fs, TestFileName,
|
||||
Diagnostics::ConsoleConsumer());
|
||||
ASSERT_TRUE(buffer);
|
||||
|
||||
EXPECT_EQ(TestFileName, buffer->filename());
|
||||
@@ -57,8 +57,8 @@ TEST(SourceBufferTest, EmptyFile) {
|
||||
CARBON_CHECK(fs.addFile(TestFileName, /*ModificationTime=*/0,
|
||||
llvm::MemoryBuffer::getMemBuffer("")));
|
||||
|
||||
auto buffer =
|
||||
SourceBuffer::MakeFromFile(fs, TestFileName, ConsoleDiagnosticConsumer());
|
||||
auto buffer = SourceBuffer::MakeFromFile(fs, TestFileName,
|
||||
Diagnostics::ConsoleConsumer());
|
||||
ASSERT_TRUE(buffer);
|
||||
|
||||
EXPECT_EQ(TestFileName, buffer->filename());
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace Carbon::Testing {
|
||||
|
||||
auto CompileHelper::GetTokenizedBuffer(llvm::StringRef text,
|
||||
DiagnosticConsumer* consumer)
|
||||
Diagnostics::Consumer* consumer)
|
||||
-> Lex::TokenizedBuffer& {
|
||||
auto& source = GetSourceBuffer(text);
|
||||
|
||||
@@ -18,7 +18,7 @@ auto CompileHelper::GetTokenizedBuffer(llvm::StringRef text,
|
||||
}
|
||||
|
||||
auto CompileHelper::GetTokenizedBufferWithSharedValueStore(
|
||||
llvm::StringRef text, DiagnosticConsumer* consumer)
|
||||
llvm::StringRef text, Diagnostics::Consumer* consumer)
|
||||
-> std::pair<Lex::TokenizedBuffer&, SharedValueStores&> {
|
||||
auto& tokens = GetTokenizedBuffer(text, consumer);
|
||||
return {tokens, value_store_storage_.front()};
|
||||
|
||||
@@ -21,12 +21,12 @@ class CompileHelper {
|
||||
public:
|
||||
// Returns the result of lex.
|
||||
auto GetTokenizedBuffer(llvm::StringRef text,
|
||||
DiagnosticConsumer* consumer = nullptr)
|
||||
Diagnostics::Consumer* consumer = nullptr)
|
||||
-> Lex::TokenizedBuffer&;
|
||||
|
||||
// Returns the result of lex along with shared values.
|
||||
auto GetTokenizedBufferWithSharedValueStore(
|
||||
llvm::StringRef text, DiagnosticConsumer* consumer = nullptr)
|
||||
llvm::StringRef text, Diagnostics::Consumer* consumer = nullptr)
|
||||
-> std::pair<Lex::TokenizedBuffer&, SharedValueStores&>;
|
||||
|
||||
// Returns the result of parse.
|
||||
@@ -44,7 +44,7 @@ class CompileHelper {
|
||||
auto GetSourceBuffer(llvm::StringRef text) -> SourceBuffer&;
|
||||
|
||||
// Diagnostics will be printed to console.
|
||||
DiagnosticConsumer& consumer_ = ConsoleDiagnosticConsumer();
|
||||
Diagnostics::Consumer& consumer_ = Diagnostics::ConsoleConsumer();
|
||||
|
||||
// An index to generate unique filenames.
|
||||
int file_index_ = 0;
|
||||
|
||||
Reference in New Issue
Block a user