Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "llvm/Support/SourceMgr.h"

namespace swift {
class DiagnosticArgument;
class SourceManager;
enum class DiagID : uint32_t;

Expand Down Expand Up @@ -87,19 +88,23 @@ class DiagnosticConsumer {
///
/// \param Kind The severity of the diagnostic (error, warning, note).
///
/// \param Text The diagnostic text.
/// \param FormatArgs The diagnostic format string arguments.
///
/// \param Info Extra information associated with the diagnostic.
virtual void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
DiagnosticKind Kind, StringRef Text,
DiagnosticKind Kind,
StringRef FormatString,
ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info) = 0;
};

/// \brief DiagnosticConsumer that discards all diagnostics.
class NullDiagnosticConsumer : public DiagnosticConsumer {
public:
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
DiagnosticKind Kind, StringRef Text,
DiagnosticKind Kind,
StringRef FormatString,
ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info) override;
};

Expand Down
26 changes: 25 additions & 1 deletion include/swift/AST/DiagnosticEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#include "swift/AST/TypeLoc.h"
#include "swift/AST/DeclNameLoc.h"
#include "swift/Basic/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticConsumer.h"

namespace swift {
class Decl;
Expand Down Expand Up @@ -260,6 +260,23 @@ namespace swift {
}
};

struct DiagnosticFormatOptions {
const std::string OpeningQuotationMark;
const std::string ClosingQuotationMark;
const std::string AKAFormatString;

DiagnosticFormatOptions(std::string OpeningQuotationMark,
std::string ClosingQuotationMark,
std::string AKAFormatString)
: OpeningQuotationMark(OpeningQuotationMark),
ClosingQuotationMark(ClosingQuotationMark),
AKAFormatString(AKAFormatString) {}

DiagnosticFormatOptions()
: OpeningQuotationMark("'"), ClosingQuotationMark("'"),
AKAFormatString("'%1$s' (aka '%2$s')") {}
};

/// Diagnostic - This is a specific instance of a diagnostic along with all of
/// the DiagnosticArguments that it requires.
class Diagnostic {
Expand Down Expand Up @@ -723,6 +740,13 @@ namespace swift {
/// \returns true if diagnostic is marked with PointsToFirstBadToken
/// option.
bool isDiagnosticPointsToFirstBadToken(DiagID id) const;

/// \brief Format the given diagnostic text and place the result in the given
/// buffer.
static void formatDiagnosticText(
llvm::raw_ostream &Out, StringRef InText,
ArrayRef<DiagnosticArgument> FormatArgs,
DiagnosticFormatOptions FormatOpts = DiagnosticFormatOptions());

private:
/// \brief Flush the active diagnostic.
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Basic/DiagnosticOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#ifndef SWIFT_BASIC_DIAGNOSTICOPTIONS_H
#define SWIFT_BASIC_DIAGNOSTICOPTIONS_H

#include "llvm/ADT/Hashing.h"

namespace swift {

/// Options for controlling diagnostics.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Frontend/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
#ifndef SWIFT_FRONTEND_H
#define SWIFT_FRONTEND_H

#include "swift/Basic/DiagnosticConsumer.h"
#include "swift/Basic/DiagnosticOptions.h"
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/SourceManager.h"
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/LinkLibrary.h"
Expand Down
6 changes: 4 additions & 2 deletions include/swift/Frontend/PrintingDiagnosticConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#define SWIFT_PRINTINGDIAGNOSTICCONSUMER_H

#include "swift/Basic/LLVM.h"
#include "swift/Basic/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticConsumer.h"

#include "llvm/Support/raw_ostream.h"

Expand All @@ -35,7 +35,9 @@ class PrintingDiagnosticConsumer : public DiagnosticConsumer {
Stream(stream) { }

virtual void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
DiagnosticKind Kind, StringRef Text,
DiagnosticKind Kind,
StringRef FormatString,
ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info) override;

void forceColors() {
Expand Down
1 change: 1 addition & 0 deletions lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ add_swift_library(swiftAST STATIC
DeclContext.cpp
DeclNameLoc.cpp
DefaultArgumentKind.cpp
DiagnosticConsumer.cpp
DiagnosticEngine.cpp
DiagnosticList.cpp
DocComment.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,23 @@
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "swift-basic"
#include "swift/Basic/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/AST/DiagnosticEngine.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;

DiagnosticConsumer::~DiagnosticConsumer() { }

void NullDiagnosticConsumer::handleDiagnostic(SourceManager &SM,
SourceLoc Loc,
DiagnosticKind Kind,
StringRef Text,
const DiagnosticInfo &Info) {
DEBUG(llvm::dbgs() << "NullDiagnosticConsumer received diagnostic: "
<< Text << "\n");
void NullDiagnosticConsumer::handleDiagnostic(
SourceManager &SM, SourceLoc Loc, DiagnosticKind Kind,
StringRef FormatString, ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info) {
DEBUG({
llvm::dbgs() << "NullDiagnosticConsumer received diagnostic: ";
DiagnosticEngine::formatDiagnosticText(llvm::dbgs(), FormatString,
FormatArgs);
llvm::dbgs() << "\n";
});
}
72 changes: 39 additions & 33 deletions lib/AST/DiagnosticEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Format.h"

using namespace swift;

Expand Down Expand Up @@ -288,10 +289,6 @@ skipToDelimiter(StringRef &Text, char Delim, bool *FoundDelim = nullptr) {
return Result;
}

static void formatDiagnosticText(StringRef InText,
ArrayRef<DiagnosticArgument> Args,
llvm::raw_ostream &Out);

/// Handle the integer 'select' modifier. This is used like this:
/// %select{foo|bar|baz}2. This means that the integer argument "%2" has a
/// value from 0-2. If the value is 0, the diagnostic prints 'foo'.
Expand All @@ -300,14 +297,15 @@ static void formatDiagnosticText(StringRef InText,
static void formatSelectionArgument(StringRef ModifierArguments,
ArrayRef<DiagnosticArgument> Args,
unsigned SelectedIndex,
DiagnosticFormatOptions FormatOpts,
llvm::raw_ostream &Out) {
bool foundPipe = false;
do {
assert((!ModifierArguments.empty() || foundPipe) &&
"Index beyond bounds in %select modifier");
StringRef Text = skipToDelimiter(ModifierArguments, '|', &foundPipe);
if (SelectedIndex == 0) {
formatDiagnosticText(Text, Args, Out);
DiagnosticEngine::formatDiagnosticText(Out, Text, Args, FormatOpts);
break;
}
--SelectedIndex;
Expand All @@ -321,14 +319,15 @@ static void formatDiagnosticArgument(StringRef Modifier,
StringRef ModifierArguments,
ArrayRef<DiagnosticArgument> Args,
unsigned ArgIndex,
DiagnosticFormatOptions FormatOpts,
llvm::raw_ostream &Out) {
const DiagnosticArgument &Arg = Args[ArgIndex];
switch (Arg.getKind()) {
case DiagnosticArgumentKind::Integer:
if (Modifier == "select") {
assert(Arg.getAsInteger() >= 0 && "Negative selection index");
formatSelectionArgument(ModifierArguments, Args, Arg.getAsInteger(),
Out);
formatSelectionArgument(ModifierArguments, Args, Arg.getAsInteger(),
FormatOpts, Out);
} else if (Modifier == "s") {
if (Arg.getAsInteger() != 1)
Out << 's';
Expand All @@ -340,8 +339,8 @@ static void formatDiagnosticArgument(StringRef Modifier,

case DiagnosticArgumentKind::Unsigned:
if (Modifier == "select") {
formatSelectionArgument(ModifierArguments, Args, Arg.getAsUnsigned(),
Out);
formatSelectionArgument(ModifierArguments, Args, Arg.getAsUnsigned(),
FormatOpts, Out);
} else if (Modifier == "s") {
if (Arg.getAsUnsigned() != 1)
Out << 's';
Expand All @@ -358,14 +357,15 @@ static void formatDiagnosticArgument(StringRef Modifier,

case DiagnosticArgumentKind::Identifier:
assert(Modifier.empty() && "Improper modifier for identifier argument");
Out << '\'';
Out << FormatOpts.OpeningQuotationMark;
Arg.getAsIdentifier().printPretty(Out);
Out << '\'';
Out << FormatOpts.ClosingQuotationMark;
break;

case DiagnosticArgumentKind::ObjCSelector:
assert(Modifier.empty() && "Improper modifier for selector argument");
Out << '\'' << Arg.getAsObjCSelector() << '\'';
Out << FormatOpts.OpeningQuotationMark << Arg.getAsObjCSelector()
<< FormatOpts.ClosingQuotationMark;
break;

case DiagnosticArgumentKind::ValueDecl:
Expand All @@ -380,8 +380,6 @@ static void formatDiagnosticArgument(StringRef Modifier,
// Strip extraneous parentheses; they add no value.
auto type = Arg.getAsType()->getWithoutParens();
std::string typeName = type->getString();
Out << '\'' << typeName << '\'';


// Decide whether to show the desugared type or not. We filter out some
// cases to avoid too much noise.
Expand Down Expand Up @@ -409,13 +407,22 @@ static void formatDiagnosticArgument(StringRef Modifier,
if (showAKA && type->hasTypeParameter())
showAKA = false;

if (showAKA)
Out << " (aka '" << type->getCanonicalType() << "')";
if (showAKA) {
llvm::SmallString<256> AkaText;
llvm::raw_svector_ostream OutAka(AkaText);
OutAka << type->getCanonicalType();
Out << llvm::format(FormatOpts.AKAFormatString.c_str(), typeName.c_str(),
AkaText.c_str());
} else {
Out << FormatOpts.OpeningQuotationMark << typeName
<< FormatOpts.ClosingQuotationMark;
}
break;
}
case DiagnosticArgumentKind::TypeRepr:
assert(Modifier.empty() && "Improper modifier for TypeRepr argument");
Out << '\'' << Arg.getAsTypeRepr() << '\'';
Out << FormatOpts.OpeningQuotationMark << Arg.getAsTypeRepr()
<< FormatOpts.ClosingQuotationMark;
break;
case DiagnosticArgumentKind::PatternKind:
assert(Modifier.empty() && "Improper modifier for PatternKind argument");
Expand All @@ -424,7 +431,8 @@ static void formatDiagnosticArgument(StringRef Modifier,
case DiagnosticArgumentKind::StaticSpellingKind:
if (Modifier == "select") {
formatSelectionArgument(ModifierArguments, Args,
unsigned(Arg.getAsStaticSpellingKind()), Out);
unsigned(Arg.getAsStaticSpellingKind()),
FormatOpts, Out);
} else {
assert(Modifier.empty() &&
"Improper modifier for StaticSpellingKind argument");
Expand All @@ -442,7 +450,9 @@ static void formatDiagnosticArgument(StringRef Modifier,
assert(Modifier.empty() &&
"Improper modifier for DeclAttribute argument");
if (Arg.getAsDeclAttribute()->isDeclModifier())
Out << '\'' << Arg.getAsDeclAttribute()->getAttrName() << '\'';
Out << FormatOpts.OpeningQuotationMark
<< Arg.getAsDeclAttribute()->getAttrName()
<< FormatOpts.ClosingQuotationMark;
else
Out << '@' << Arg.getAsDeclAttribute()->getAttrName();
break;
Expand All @@ -454,16 +464,17 @@ static void formatDiagnosticArgument(StringRef Modifier,
break;
case DiagnosticArgumentKind::LayoutConstraint:
assert(Modifier.empty() && "Improper modifier for LayoutConstraint argument");
Out << '\'' << Arg.getAsLayoutConstraint() << '\'';
Out << FormatOpts.OpeningQuotationMark << Arg.getAsLayoutConstraint()
<< FormatOpts.ClosingQuotationMark;
break;
}
}

/// \brief Format the given diagnostic text and place the result in the given
/// buffer.
static void formatDiagnosticText(StringRef InText,
ArrayRef<DiagnosticArgument> Args,
llvm::raw_ostream &Out) {
void DiagnosticEngine::formatDiagnosticText(
llvm::raw_ostream &Out, StringRef InText, ArrayRef<DiagnosticArgument> Args,
DiagnosticFormatOptions FormatOpts) {
while (!InText.empty()) {
size_t Percent = InText.find('%');
if (Percent == StringRef::npos) {
Expand Down Expand Up @@ -515,7 +526,8 @@ static void formatDiagnosticText(StringRef InText,
InText = InText.substr(Length);

// Convert the argument to a string.
formatDiagnosticArgument(Modifier, ModifierArguments, Args, ArgIndex, Out);
formatDiagnosticArgument(Modifier, ModifierArguments, Args, ArgIndex,
FormatOpts, Out);
}
}

Expand Down Expand Up @@ -736,21 +748,15 @@ void DiagnosticEngine::emitDiagnostic(const Diagnostic &diagnostic) {
}
}

// Actually substitute the diagnostic arguments into the diagnostic text.
llvm::SmallString<256> Text;
{
llvm::raw_svector_ostream Out(Text);
formatDiagnosticText(diagnosticStrings[(unsigned)diagnostic.getID()],
diagnostic.getArgs(), Out);
}

// Pass the diagnostic off to the consumer.
DiagnosticInfo Info;
Info.ID = diagnostic.getID();
Info.Ranges = diagnostic.getRanges();
Info.FixIts = diagnostic.getFixIts();
for (auto &Consumer : Consumers) {
Consumer->handleDiagnostic(SourceMgr, loc, toDiagnosticKind(behavior), Text,
Consumer->handleDiagnostic(SourceMgr, loc, toDiagnosticKind(behavior),
diagnosticStrings[(unsigned)Info.ID],
diagnostic.getArgs(),
Info);
}
}
Expand Down
1 change: 0 additions & 1 deletion lib/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ set(version_inc_files
add_swift_library(swiftBasic STATIC
Cache.cpp
ClusteredBitVector.cpp
DiagnosticConsumer.cpp
DiverseStack.cpp
Edit.cpp
EditorPlaceholder.cpp
Expand Down
Loading