mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
DiagnosticEngine: Print the ID of the wrapped, not wrapper, diagnostic
This commit is contained in:
@@ -1530,16 +1530,17 @@ namespace swift {
|
||||
public:
|
||||
DiagnosticKind declaredDiagnosticKindFor(const DiagID id);
|
||||
|
||||
/// Get a localized format string for a given `DiagID`. If no localization
|
||||
/// available returns the default string for that `DiagID`.
|
||||
llvm::StringRef diagnosticStringFor(DiagID id);
|
||||
/// Get a localized format string for the given `DiagID`. If no localization
|
||||
/// is available, returns the default string.
|
||||
llvm::StringRef getFormatStringForDiagnostic(DiagID id);
|
||||
|
||||
/// Get a localized format string with an optional diagnostic name appended
|
||||
/// to it. The diagnostic name type is defined by
|
||||
/// `PrintDiagnosticNamesMode`.
|
||||
llvm::StringRef diagnosticStringWithNameFor(
|
||||
DiagID id, DiagGroupID groupID,
|
||||
PrintDiagnosticNamesMode printDiagnosticNamesMode);
|
||||
/// Get a localized format string for the given diagnostic. If no
|
||||
/// localization is available, returns the default string.
|
||||
///
|
||||
/// \param includeDiagnosticName Whether to at all consider embedding the
|
||||
/// name of the diagnostic identifier or group, per the setting.
|
||||
llvm::StringRef getFormatStringForDiagnostic(const Diagnostic &diagnostic,
|
||||
bool includeDiagnosticName);
|
||||
|
||||
static llvm::StringRef diagnosticIDStringFor(const DiagID id);
|
||||
|
||||
|
||||
@@ -1429,17 +1429,11 @@ DiagnosticEngine::diagnosticInfoForDiagnostic(const Diagnostic &diagnostic,
|
||||
}
|
||||
}
|
||||
|
||||
llvm::StringRef format;
|
||||
if (includeDiagnosticName) {
|
||||
format =
|
||||
diagnosticStringWithNameFor(diagnostic.getID(), groupID,
|
||||
getPrintDiagnosticNamesMode());
|
||||
} else {
|
||||
format = diagnosticStringFor(diagnostic.getID());
|
||||
}
|
||||
auto formatString =
|
||||
getFormatStringForDiagnostic(diagnostic, includeDiagnosticName);
|
||||
|
||||
return DiagnosticInfo(diagnostic.getID(), loc, toDiagnosticKind(behavior),
|
||||
format, diagnostic.getArgs(), Category,
|
||||
formatString, diagnostic.getArgs(), Category,
|
||||
getDefaultDiagnosticLoc(),
|
||||
/*child note info*/ {}, diagnostic.getRanges(), fixIts,
|
||||
diagnostic.isChildNote());
|
||||
@@ -1622,7 +1616,7 @@ DiagnosticKind DiagnosticEngine::declaredDiagnosticKindFor(const DiagID id) {
|
||||
return storedDiagnosticInfos[(unsigned)id].kind;
|
||||
}
|
||||
|
||||
llvm::StringRef DiagnosticEngine::diagnosticStringFor(DiagID id) {
|
||||
llvm::StringRef DiagnosticEngine::getFormatStringForDiagnostic(DiagID id) {
|
||||
llvm::StringRef message = diagnosticStrings[(unsigned)id];
|
||||
if (auto localizationProducer = localization.get()) {
|
||||
message = localizationProducer->getMessageOr(id, message);
|
||||
@@ -1630,10 +1624,16 @@ llvm::StringRef DiagnosticEngine::diagnosticStringFor(DiagID id) {
|
||||
return message;
|
||||
}
|
||||
|
||||
llvm::StringRef DiagnosticEngine::diagnosticStringWithNameFor(
|
||||
DiagID id, DiagGroupID groupID,
|
||||
PrintDiagnosticNamesMode printDiagnosticNamesMode) {
|
||||
auto message = diagnosticStringFor(id);
|
||||
llvm::StringRef
|
||||
DiagnosticEngine::getFormatStringForDiagnostic(const Diagnostic &diagnostic,
|
||||
bool includeDiagnosticName) {
|
||||
auto diagID = diagnostic.getID();
|
||||
auto message = getFormatStringForDiagnostic(diagID);
|
||||
|
||||
if (!includeDiagnosticName) {
|
||||
return message;
|
||||
}
|
||||
|
||||
auto formatMessageWithName = [&](StringRef message, StringRef name) {
|
||||
const int additionalCharsLength = 3; // ' ', '[', ']'
|
||||
std::string messageWithName;
|
||||
@@ -1648,16 +1648,28 @@ llvm::StringRef DiagnosticEngine::diagnosticStringWithNameFor(
|
||||
switch (printDiagnosticNamesMode) {
|
||||
case PrintDiagnosticNamesMode::None:
|
||||
break;
|
||||
case PrintDiagnosticNamesMode::Identifier:
|
||||
message = formatMessageWithName(message, diagnosticIDStringFor(id));
|
||||
case PrintDiagnosticNamesMode::Identifier: {
|
||||
// If this diagnostic is a wrapper for another diagnostic, use the ID of
|
||||
// the wrapped diagnostic.
|
||||
for (const auto &arg : diagnostic.getArgs()) {
|
||||
if (arg.getKind() == DiagnosticArgumentKind::Diagnostic) {
|
||||
diagID = arg.getAsDiagnostic()->ID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
message = formatMessageWithName(message, diagnosticIDStringFor(diagID));
|
||||
break;
|
||||
}
|
||||
case PrintDiagnosticNamesMode::Group:
|
||||
auto groupID = diagnostic.getGroupID();
|
||||
if (groupID != DiagGroupID::no_group) {
|
||||
message =
|
||||
formatMessageWithName(message, getDiagGroupInfoByID(groupID).name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ bool CodeCompletionDiagnostics::getDiagnostics(
|
||||
typename swift::detail::PassArgument<ArgTypes>::type... VArgs) {
|
||||
DiagID id = ID.ID;
|
||||
std::vector<DiagnosticArgument> DiagArgs{std::move(VArgs)...};
|
||||
auto format = Engine.diagnosticStringFor(id);
|
||||
auto format = Engine.getFormatStringForDiagnostic(id);
|
||||
DiagnosticEngine::formatDiagnosticText(Out, format, DiagArgs);
|
||||
severity = getSeverity(Engine.declaredDiagnosticKindFor(id));
|
||||
|
||||
|
||||
@@ -1086,7 +1086,7 @@ public:
|
||||
// Emit a specific unavailable message when we know why a decl can't be
|
||||
// exposed, or a generic message otherwise.
|
||||
auto diagString =
|
||||
M.getASTContext().Diags.diagnosticStringFor(diag.getID());
|
||||
M.getASTContext().Diags.getFormatStringForDiagnostic(diag.getID());
|
||||
DiagnosticEngine::formatDiagnosticText(os, diagString, diag.getArgs(),
|
||||
DiagnosticFormatOptions());
|
||||
os << "\");\n";
|
||||
|
||||
@@ -8,6 +8,7 @@ add_swift_unittest(SwiftASTTests
|
||||
DiagnosticBehaviorTests.cpp
|
||||
DiagnosticConsumerTests.cpp
|
||||
DiagnosticGroupsTests.cpp
|
||||
DiagnosticInfoTests.cpp
|
||||
SourceLocTests.cpp
|
||||
TestContext.cpp
|
||||
TypeMatchTests.cpp
|
||||
|
||||
@@ -64,7 +64,7 @@ TEST(DiagnosticBehavior, WarnUntilSwiftLangMode) {
|
||||
[](DiagnosticEngine &diags, const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.Kind, DiagnosticKind::Error);
|
||||
EXPECT_EQ(info.FormatString,
|
||||
diags.diagnosticStringFor(
|
||||
diags.getFormatStringForDiagnostic(
|
||||
diag::error_immediate_mode_missing_stdlib.ID));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
@@ -77,12 +77,12 @@ TEST(DiagnosticBehavior, WarnUntilSwiftLangMode) {
|
||||
},
|
||||
[](DiagnosticEngine &diags, const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.Kind, DiagnosticKind::Warning);
|
||||
EXPECT_EQ(info.FormatString,
|
||||
diags.diagnosticStringFor(diag::error_in_swift_lang_mode.ID));
|
||||
EXPECT_EQ(info.FormatString, diags.getFormatStringForDiagnostic(
|
||||
diag::error_in_swift_lang_mode.ID));
|
||||
|
||||
auto wrappedDiagInfo = info.FormatArgs.front().getAsDiagnostic();
|
||||
EXPECT_EQ(wrappedDiagInfo->FormatString,
|
||||
diags.diagnosticStringFor(
|
||||
diags.getFormatStringForDiagnostic(
|
||||
diag::error_immediate_mode_missing_stdlib.ID));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
@@ -96,12 +96,12 @@ TEST(DiagnosticBehavior, WarnUntilSwiftLangMode) {
|
||||
[](DiagnosticEngine &diags, const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.Kind, DiagnosticKind::Warning);
|
||||
EXPECT_EQ(info.FormatString,
|
||||
diags.diagnosticStringFor(
|
||||
diags.getFormatStringForDiagnostic(
|
||||
diag::error_in_a_future_swift_lang_mode.ID));
|
||||
|
||||
auto wrappedDiagInfo = info.FormatArgs.front().getAsDiagnostic();
|
||||
EXPECT_EQ(wrappedDiagInfo->FormatString,
|
||||
diags.diagnosticStringFor(
|
||||
diags.getFormatStringForDiagnostic(
|
||||
diag::error_immediate_mode_missing_stdlib.ID));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
|
||||
@@ -63,54 +63,6 @@ static void diagnosticGroupsTestCase(
|
||||
EXPECT_EQ(count, expectedNumCallbackCalls);
|
||||
}
|
||||
|
||||
TEST(DiagnosticGroups, PrintDiagnosticGroups) {
|
||||
// Test that we append the correct group in the format string.
|
||||
diagnosticGroupsTestCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Group);
|
||||
|
||||
TestDiagnostic diagnostic(diag::error_immediate_mode_missing_stdlib.ID,
|
||||
DiagGroupID::DeprecatedDeclaration);
|
||||
diags.diagnose(SourceLoc(), diagnostic);
|
||||
},
|
||||
[](const DiagnosticInfo &info) {
|
||||
EXPECT_TRUE(info.FormatString.ends_with(" [DeprecatedDeclaration]"));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
|
||||
diagnosticGroupsTestCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Group);
|
||||
|
||||
TestDiagnostic diagnostic(diag::error_immediate_mode_missing_stdlib.ID,
|
||||
DiagGroupID::no_group);
|
||||
diags.diagnose(SourceLoc(), diagnostic);
|
||||
},
|
||||
[](const DiagnosticInfo &info) {
|
||||
EXPECT_FALSE(info.FormatString.ends_with("]"));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
TEST(DiagnosticGroups, DiagnosticsWrappersInheritGroups) {
|
||||
// Test that we don't loose the group of a diagnostic when it gets wrapped in
|
||||
// another one.
|
||||
diagnosticGroupsTestCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Group);
|
||||
|
||||
TestDiagnostic diagnostic(diag::error_immediate_mode_missing_stdlib.ID,
|
||||
DiagGroupID::DeprecatedDeclaration);
|
||||
diags.diagnose(SourceLoc(), diagnostic)
|
||||
.limitBehaviorUntilSwiftVersion(DiagnosticBehavior::Warning, 99);
|
||||
},
|
||||
[](const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.ID, diag::error_in_a_future_swift_lang_mode.ID);
|
||||
EXPECT_TRUE(info.FormatString.ends_with(" [DeprecatedDeclaration]"));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
TEST(DiagnosticGroups, TargetAll) {
|
||||
// Test that uncategorized diagnostics are escalated when escalating all
|
||||
// warnings.
|
||||
|
||||
168
unittests/AST/DiagnosticInfoTests.cpp
Normal file
168
unittests/AST/DiagnosticInfoTests.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
//===--- DiagnosticInfoTests.cpp --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2025 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "swift/AST/DiagnosticEngine.h"
|
||||
#include "swift/AST/DiagnosticGroups.h"
|
||||
#include "swift/AST/DiagnosticsFrontend.h"
|
||||
#include "swift/Basic/SourceManager.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
namespace {
|
||||
class TestDiagnosticConsumer : public DiagnosticConsumer {
|
||||
llvm::function_ref<void(const DiagnosticInfo &)> callback;
|
||||
|
||||
public:
|
||||
TestDiagnosticConsumer(decltype(callback) callback) : callback(callback) {}
|
||||
|
||||
void handleDiagnostic(SourceManager &SM,
|
||||
const DiagnosticInfo &Info) override {
|
||||
this->callback(Info);
|
||||
}
|
||||
};
|
||||
|
||||
struct TestDiagnostic : public Diagnostic {
|
||||
TestDiagnostic(DiagID ID, DiagGroupID GroupID) : Diagnostic(ID, GroupID) {}
|
||||
};
|
||||
|
||||
static void
|
||||
testCase(llvm::function_ref<void(DiagnosticEngine &)> diagnose,
|
||||
llvm::function_ref<void(DiagnosticEngine &, const DiagnosticInfo &)>
|
||||
callback,
|
||||
unsigned expectedNumCallbackCalls) {
|
||||
SourceManager sourceMgr;
|
||||
DiagnosticEngine diags(sourceMgr);
|
||||
|
||||
unsigned count = 0;
|
||||
|
||||
const auto countingCallback = [&](const DiagnosticInfo &info) {
|
||||
++count;
|
||||
callback(diags, info);
|
||||
};
|
||||
|
||||
TestDiagnosticConsumer consumer(countingCallback);
|
||||
diags.addConsumer(consumer);
|
||||
diagnose(diags);
|
||||
diags.removeConsumer(consumer);
|
||||
|
||||
EXPECT_EQ(count, expectedNumCallbackCalls);
|
||||
}
|
||||
|
||||
// MARK: PrintDiagnosticNamesMode
|
||||
|
||||
TEST(DiagnosticInfo, PrintDiagnosticNamesMode_None) {
|
||||
// Test that we don't embed anything in the format string if told so.
|
||||
testCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::None);
|
||||
|
||||
TestDiagnostic diagnostic(diag::error_immediate_mode_missing_stdlib.ID,
|
||||
DiagGroupID::DeprecatedDeclaration);
|
||||
diags.diagnose(SourceLoc(), diagnostic);
|
||||
},
|
||||
[](DiagnosticEngine &diags, const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.FormatString,
|
||||
diags.getFormatStringForDiagnostic(
|
||||
diag::error_immediate_mode_missing_stdlib.ID));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
TEST(DiagnosticInfo, PrintDiagnosticNamesMode_Identifier) {
|
||||
// Test that we embed correct identifier in the format string.
|
||||
testCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Identifier);
|
||||
|
||||
diags.diagnose(SourceLoc(), diag::error_immediate_mode_missing_stdlib);
|
||||
},
|
||||
[](DiagnosticEngine &diags, const DiagnosticInfo &info) {
|
||||
EXPECT_TRUE(info.FormatString.ends_with(
|
||||
" [error_immediate_mode_missing_stdlib]"));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
TEST(DiagnosticInfo, PrintDiagnosticNamesMode_Identifier_WrappedDiag) {
|
||||
// For a wrapper diagnostic, test that we embed the identifier of the wrapped
|
||||
// diagnostic.
|
||||
testCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Identifier);
|
||||
|
||||
diags.diagnose(SourceLoc(), diag::error_immediate_mode_missing_stdlib)
|
||||
.limitBehaviorUntilSwiftVersion(DiagnosticBehavior::Warning, 99);
|
||||
},
|
||||
[](DiagnosticEngine &diags, const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.ID, diag::error_in_a_future_swift_lang_mode.ID);
|
||||
EXPECT_TRUE(info.FormatString.ends_with(
|
||||
" [error_immediate_mode_missing_stdlib]"));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
TEST(DiagnosticInfo, PrintDiagnosticNamesMode_Group_NoGroup) {
|
||||
// Test that we don't embed anything in the format string if the diagnostic
|
||||
// has no group.
|
||||
testCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Group);
|
||||
|
||||
TestDiagnostic diagnostic(diag::error_immediate_mode_missing_stdlib.ID,
|
||||
DiagGroupID::no_group);
|
||||
diags.diagnose(SourceLoc(), diagnostic);
|
||||
},
|
||||
[](DiagnosticEngine &diags, const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.FormatString,
|
||||
diags.getFormatStringForDiagnostic(
|
||||
diag::error_immediate_mode_missing_stdlib.ID));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
TEST(DiagnosticInfo, PrintDiagnosticNamesMode_Group) {
|
||||
// Test that we embed the correct group in the format string.
|
||||
testCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Group);
|
||||
|
||||
TestDiagnostic diagnostic(diag::error_immediate_mode_missing_stdlib.ID,
|
||||
DiagGroupID::DeprecatedDeclaration);
|
||||
diags.diagnose(SourceLoc(), diagnostic);
|
||||
},
|
||||
[](DiagnosticEngine &, const DiagnosticInfo &info) {
|
||||
EXPECT_TRUE(info.FormatString.ends_with(" [DeprecatedDeclaration]"));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
TEST(DiagnosticInfo, PrintDiagnosticNamesMode_Group_WrappedDiag) {
|
||||
// For a wrapper diagnostic, test that we embed the group name of the wrapped
|
||||
// diagnostic.
|
||||
testCase(
|
||||
[](DiagnosticEngine &diags) {
|
||||
diags.setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode::Group);
|
||||
|
||||
TestDiagnostic diagnostic(diag::error_immediate_mode_missing_stdlib.ID,
|
||||
DiagGroupID::DeprecatedDeclaration);
|
||||
diags.diagnose(SourceLoc(), diagnostic)
|
||||
.limitBehaviorUntilSwiftVersion(DiagnosticBehavior::Warning, 99);
|
||||
},
|
||||
[](DiagnosticEngine &, const DiagnosticInfo &info) {
|
||||
EXPECT_EQ(info.ID, diag::error_in_a_future_swift_lang_mode.ID);
|
||||
EXPECT_TRUE(info.FormatString.ends_with(" [DeprecatedDeclaration]"));
|
||||
},
|
||||
/*expectedNumCallbackCalls=*/1);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
Reference in New Issue
Block a user