swift-module-digester: refactor the ABI/API diagnostics to use DiagnosticEngine. NFC (#18957)

Before this patch, we used to define tooling-specific diagnostics. With adding more
checking logics, we found this mechanism hard to extend. This patch
eliminates the home-made diagnostics model to use the one from compiler, which provides
several benefits: less boiler-templates, better integration with DiagnosticConsumer,
and easy ordering of detected issues.
This commit is contained in:
Xi Ge
2018-08-24 13:11:32 -07:00
committed by GitHub
parent 574b7f45be
commit e4388af6be
15 changed files with 349 additions and 290 deletions

View File

@@ -672,6 +672,19 @@ namespace swift {
return diagnose(Loc, Diagnostic(ID, std::move(Args)...));
}
/// \brief Emit a diagnostic with the given set of diagnostic arguments.
///
/// \param ID The diagnostic to be emitted.
///
/// \param Args The diagnostic arguments, which will be converted to
/// the types expected by the diagnostic \p ID.
template<typename ...ArgTypes>
InFlightDiagnostic
diagnose(Diag<ArgTypes...> ID,
typename detail::PassArgument<ArgTypes>::type... Args) {
return diagnose(SourceLoc(), ID, std::move(Args)...);
}
/// \brief Emit a diagnostic with the given set of diagnostic arguments.
///
/// \param Loc The declaration name location to which the

View File

@@ -49,6 +49,7 @@
#include "DiagnosticsFrontend.def"
#include "DiagnosticsDriver.def"
#include "DiagnosticsRefactoring.def"
#include "DiagnosticsModuleDiffer.def"
#undef DIAG_NO_UNDEF

View File

@@ -0,0 +1,62 @@
//===--- DiagnosticsModuleDiffer.def - Diagnostics Text ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// This file defines diagnostics emitted during diffing two Swift modules.
// Each diagnostic is described using one of three kinds (error, warning, or
// note) along with a unique identifier, category, options, and text, and is
// followed by a signature describing the diagnostic argument kinds.
//
//===----------------------------------------------------------------------===//
#if !(defined(DIAG) || (defined(ERROR) && defined(WARNING) && defined(NOTE)))
# error Must define either DIAG or the set {ERROR,WARNING,NOTE}
#endif
#ifndef ERROR
# define ERROR(ID,Options,Text,Signature) \
DIAG(ERROR,ID,Options,Text,Signature)
#endif
#ifndef WARNING
# define WARNING(ID,Options,Text,Signature) \
DIAG(WARNING,ID,Options,Text,Signature)
#endif
#ifndef NOTE
# define NOTE(ID,Options,Text,Signature) \
DIAG(NOTE,ID,Options,Text,Signature)
#endif
ERROR(generic_sig_change,none,"%0 has generic signature change from %1 to %2", (StringRef, StringRef, StringRef))
ERROR(raw_type_change,none,"%0(%1) is now %2 representable", (StringRef, StringRef, StringRef))
ERROR(removed_decl,none,"%0 has been removed%select{| (deprecated)}1", (StringRef, bool))
ERROR(moved_decl,none,"%0 has been moved to %1", (StringRef, StringRef))
ERROR(renamed_decl,none,"%0 has been renamed to %1", (StringRef, StringRef))
ERROR(decl_type_change,none,"%0 has %1 type change from %2 to %3", (StringRef, StringRef, StringRef, StringRef))
ERROR(decl_attr_change,none,"%0 changes from %1 to %2", (StringRef, StringRef, StringRef))
ERROR(decl_new_attr,none,"%0 is now %1", (StringRef, StringRef))
#ifndef DIAG_NO_UNDEF
# if defined(DIAG)
# undef DIAG
# endif
# undef NOTE
# undef WARNING
# undef ERROR
#endif

View File

@@ -0,0 +1,32 @@
//===--- DiagnosticsModuleDiffer.h - Diagnostic Definitions ----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
/// \file
/// \brief This file defines diagnostics for the Swift module differ.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_DIAGNOSTICS_MODULE_DIFFER_H
#define SWIFT_DIAGNOSTICS_MODULE_DIFFER_H
#include "swift/AST/DiagnosticsCommon.h"
namespace swift {
namespace diag {
// Declare common diagnostics objects with their appropriate types.
#define DIAG(KIND,ID,Options,Text,Signature) \
extern detail::DiagWithArguments<void Signature>::type ID;
#include "DiagnosticsModuleDiffer.def"
}
}
#endif

View File

@@ -60,6 +60,11 @@ raw_ostream &operator<<(raw_ostream &Out, const NodeAnnotation Value);
// Redefine << so that we can output the name of the node kind.
raw_ostream &operator<<(raw_ostream &Out, const SDKNodeKind Value);
StringRef getDeclKindStr(const DeclKind Value);
// Redefine << so that we can output the name of decl kind.
raw_ostream &operator<<(raw_ostream &Out, const DeclKind Value);
struct APIDiffItem {
virtual void streamDef(llvm::raw_ostream &S) const = 0;
virtual APIDiffItemKind getKind() const = 0;

View File

@@ -23,7 +23,7 @@ using namespace swift;
using namespace ide;
using namespace api;
inline raw_ostream &swift::ide::api::
raw_ostream &swift::ide::api::
operator<<(raw_ostream &Out, const SDKNodeKind Value) {
switch (Value) {
#define NODE_KIND(Name, Value) case SDKNodeKind::Name: return Out << #Value;
@@ -32,13 +32,26 @@ operator<<(raw_ostream &Out, const SDKNodeKind Value) {
llvm_unreachable("Undefined SDK node kind.");
}
inline raw_ostream &swift::ide::api::
raw_ostream &swift::ide::api::
operator<<(raw_ostream &Out, const NodeAnnotation Value) {
#define NODE_ANNOTATION(X) if (Value == NodeAnnotation::X) { return Out << #X; }
#include "swift/IDE/DigesterEnums.def"
llvm_unreachable("Undefined SDK node kind.");
}
StringRef swift::ide::api::getDeclKindStr(const DeclKind Value) {
switch (Value) {
#define DECL(X, PARENT) case DeclKind::X: return #X;
#include "swift/AST/DeclNodes.def"
}
llvm_unreachable("Unhandled DeclKind in switch.");
}
raw_ostream &swift::ide::api::operator<<(raw_ostream &Out,
const DeclKind Value) {
return Out << getDeclKindStr(Value);
}
Optional<SDKNodeKind> swift::ide::api::parseSDKNodeKind(StringRef Content) {
return llvm::StringSwitch<Optional<SDKNodeKind>>(Content)
#define NODE_KIND(NAME, VALUE) .Case(#VALUE, SDKNodeKind::NAME)

View File

@@ -11,8 +11,8 @@ cake1: Func C4.foo() has been removed
/* Moved Decls */
/* Renamed Decls */
cake1: Struct Somestruct2 has been renamed to Struct NSSomestruct2
cake1: Func S1.foo5(x:y:) has been renamed to Func S1.foo5(x:y:z:)
cake1: Struct Somestruct2 has been renamed to Struct NSSomestruct2
/* Type Changes */
cake1: Constructor S1.init(_:) has parameter 0 type change from Int to Double
@@ -20,12 +20,12 @@ cake1: Func C1.foo2(_:) has parameter 0 type change from Int to () -> ()
cake1: Func Somestruct2.foo1(_:) has parameter 0 type change from C3 to C1
/* Decl Attribute changes */
cake1: Enum IceKind is now without @_frozen
cake1: Struct C6 is now with @_fixed_layout
cake1: Class C5 is now without @objc
cake1: Var C1.CIIns1 changes from weak to strong
cake1: Var C1.CIIns2 changes from strong to weak
cake1: Enum IceKind is now without @_frozen
cake1: Func C1.foo1() is now not static
cake1: Func C5.dy_foo() is now with dynamic
cake1: Func S1.foo1() is now mutating
cake1: Func S1.foo3() is now static
cake1: Struct C6 is now with @_fixed_layout
cake1: Var C1.CIIns1 changes from weak to strong
cake1: Var C1.CIIns2 changes from strong to weak

View File

@@ -11,16 +11,16 @@ cake1: Func C4.foo() has been removed
/* Moved Decls */
/* Renamed Decls */
cake1: Struct Somestruct2 has been renamed to Struct NSSomestruct2
cake1: Func S1.foo5(x:y:) has been renamed to Func S1.foo5(x:y:z:)
cake1: Struct Somestruct2 has been renamed to Struct NSSomestruct2
/* Type Changes */
cake1: Constructor S1.init(_:) has parameter 0 type change from Int to Double
cake1: Func C1.foo2(_:) has parameter 0 type change from Int to () -> ()
/* Decl Attribute changes */
cake1: Var C1.CIIns1 changes from weak to strong
cake1: Var C1.CIIns2 changes from strong to weak
cake1: Func C1.foo1() is now not static
cake1: Func S1.foo1() is now mutating
cake1: Func S1.foo3() is now static
cake1: Var C1.CIIns1 changes from weak to strong
cake1: Var C1.CIIns2 changes from strong to weak

View File

@@ -4,17 +4,6 @@
/* RawRepresentable Changes */
/* Removed Decls */
TypeAlias AbsoluteValuable has been removed
TypeAlias BitwiseOperations has been removed (deprecated)
TypeAlias IntMax has been removed
TypeAlias Integer has been removed
TypeAlias IntegerArithmetic has been removed
TypeAlias SignedNumber has been removed
TypeAlias StringProtocol.UTF16Index has been removed (deprecated)
TypeAlias StringProtocol.UTF8Index has been removed (deprecated)
TypeAlias StringProtocol.UnicodeScalarIndex has been removed (deprecated)
TypeAlias UIntMax has been removed
Var FixedWidthInteger.allZeros has been removed (deprecated)
Constructor Int.init(truncatingBitPattern:) has been removed
Constructor Int16.init(truncatingBitPattern:) has been removed
Constructor Int32.init(truncatingBitPattern:) has been removed
@@ -64,6 +53,17 @@ Func UInt32.toIntMax() has been removed
Func UInt64.toIntMax() has been removed
Func UInt8.toIntMax() has been removed
Func UnsignedInteger.toUIntMax() has been removed
TypeAlias AbsoluteValuable has been removed
TypeAlias BitwiseOperations has been removed (deprecated)
TypeAlias IntMax has been removed
TypeAlias Integer has been removed
TypeAlias IntegerArithmetic has been removed
TypeAlias SignedNumber has been removed
TypeAlias StringProtocol.UTF16Index has been removed (deprecated)
TypeAlias StringProtocol.UTF8Index has been removed (deprecated)
TypeAlias StringProtocol.UnicodeScalarIndex has been removed (deprecated)
TypeAlias UIntMax has been removed
Var FixedWidthInteger.allZeros has been removed (deprecated)
/* Moved Decls */
@@ -72,12 +72,13 @@ Func Dictionary.filter(_:obsoletedInSwift4:) has been renamed to Func Dictionary
Func Set.filter(_:obsoletedInSwift4:) has been renamed to Func Set.filter(_:)
/* Type Changes */
Var Dictionary.keys has declared type change from LazyMapCollection<[Key : Value], Key> to Dictionary<Key, Value>.Keys
Var Dictionary.values has declared type change from LazyMapCollection<[Key : Value], Value> to Dictionary<Key, Value>.Values
Constructor String.init(_:) has return type change from String? to String
Func Dictionary.filter(_:obsoletedInSwift4:) has return type change from [Dictionary<Key, Value>.Element] to [Dictionary<Key, Value>.Key : Dictionary<Key, Value>.Value]
Func Dictionary.makeIterator() has return type change from DictionaryIterator<Dictionary<Key, Value>.Key, Dictionary<Key, Value>.Value> to Dictionary<Key, Value>.Iterator
Func Set.filter(_:obsoletedInSwift4:) has return type change from [Set<Element>.Element] to Set<Element>
Func Set.makeIterator() has return type change from SetIterator<Element> to Set<Element>.Iterator
Var Dictionary.keys has declared type change from LazyMapCollection<[Key : Value], Key> to Dictionary<Key, Value>.Keys
Var Dictionary.values has declared type change from LazyMapCollection<[Key : Value], Value> to Dictionary<Key, Value>.Values
/* Decl Attribute changes */

View File

@@ -1,6 +1,7 @@
add_swift_host_tool(swift-api-digester
swift-api-digester.cpp
ModuleAnalyzerNodes.cpp
ModuleDiagsConsumer.cpp
LINK_LIBRARIES swiftFrontend swiftIDE
SWIFT_COMPONENT tools
)

View File

@@ -293,6 +293,22 @@ SDKNode *SDKNodeRoot::getInstance(SDKContext &Ctx) {
return Info.createSDKNode(SDKNodeKind::Root);
}
StringRef SDKNodeDecl::getScreenInfo() const {
auto ModuleName = getModuleName();
auto HeaderName = getHeaderName();
auto &Ctx = getSDKContext();
llvm::SmallString<64> SS;
llvm::raw_svector_ostream OS(SS);
if (Ctx.getOpts().PrintModule)
OS << ModuleName;
if (!HeaderName.empty())
OS << "(" << HeaderName << ")";
if (!OS.str().empty())
OS << ": ";
OS << getDeclKind() << " " << getFullyQualifiedName();
return Ctx.buffer(OS.str());
}
bool SDKNodeDecl::isSDKPrivate() const {
if (getName().startswith("__"))
return true;

View File

@@ -139,6 +139,7 @@ struct CheckerOptions {
bool ABI;
bool Verbose;
bool AbortOnModuleLoadFailure;
bool PrintModule;
StringRef LocationFilter;
};
@@ -303,6 +304,7 @@ public:
bool hasDeclAttribute(DeclAttrKind DAKind) const;
bool isStatic() const { return IsStatic; };
StringRef getGenericSignature() const { return GenericSig; }
StringRef getScreenInfo() const;
};
class SDKNodeRoot: public SDKNode {

View File

@@ -0,0 +1,94 @@
//===--- ModuleDiagsConsumer.cpp - Print module differ diagnostics --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// This file implements the ModuleDifferDiagsConsumer class, which displays
// diagnostics from the module differ as text to an output.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsModuleDiffer.h"
#include "ModuleDiagsConsumer.h"
using namespace swift;
namespace {
// Reproduce the DiagIDs, as we want both the size and access to the raw ids
// themselves.
enum LocalDiagID : uint32_t {
#define DIAG(KIND, ID, Options, Text, Signature) ID,
#include "swift/AST/DiagnosticsAll.def"
NumDiags
};
static StringRef getCategoryName(uint32_t ID) {
switch(ID) {
case LocalDiagID::removed_decl:
return "/* Removed Decls */";
case LocalDiagID::moved_decl:
return "/* Moved Decls */";
case LocalDiagID::renamed_decl:
return "/* Renamed Decls */";
case LocalDiagID::decl_attr_change:
case LocalDiagID::decl_new_attr:
return "/* Decl Attribute changes */";
case LocalDiagID::decl_type_change:
return "/* Type Changes */";
case LocalDiagID::raw_type_change:
return "/* RawRepresentable Changes */";
case LocalDiagID::generic_sig_change:
return "/* Generic Signature Changes */";
default:
return StringRef();
}
}
}
swift::ide::api::
ModuleDifferDiagsConsumer::ModuleDifferDiagsConsumer():
PrintingDiagnosticConsumer(llvm::errs()) {
#define DIAG(KIND, ID, Options, Text, Signature) \
auto ID = getCategoryName(LocalDiagID::ID); \
assert(!ID.empty()); \
AllDiags[ID] = std::set<std::string>();
#include "swift/AST/DiagnosticsModuleDiffer.def"
}
void swift::ide::api::
ModuleDifferDiagsConsumer::handleDiagnostic(SourceManager &SM, SourceLoc Loc,
DiagnosticKind Kind,
StringRef FormatString,
ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info) {
auto Category = getCategoryName((uint32_t)Info.ID);
if (Category.empty()) {
PrintingDiagnosticConsumer::handleDiagnostic(SM, Loc, Kind, FormatString,
FormatArgs, Info);
return;
}
llvm::SmallString<256> Text;
{
llvm::raw_svector_ostream Out(Text);
DiagnosticEngine::formatDiagnosticText(Out, FormatString, FormatArgs);
}
AllDiags[Category].insert(Text.str().str());
}
swift::ide::api::ModuleDifferDiagsConsumer::~ModuleDifferDiagsConsumer() {
for (auto &Pair: AllDiags) {
llvm::outs() << "\n";
llvm::outs() << Pair.first << "\n";
for (auto &Item: Pair.second) {
llvm::outs() << Item << "\n";
}
}
}

View File

@@ -0,0 +1,49 @@
//===--- ModuleDiagsConsumer.h - Print module differ diagnostics --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the ModuleDifferDiagsConsumer class, which displays
// diagnostics from the module differ as text to an output.
//
//===----------------------------------------------------------------------===//
#ifndef __SWIFT_MODULE_DIFFER_DIAGS_CONSUMER_H__
#define __SWIFT_MODULE_DIFFER_DIAGS_CONSUMER_H__
#include "llvm/ADT/MapVector.h"
#include "swift/Basic/LLVM.h"
#include "swift/AST/DiagnosticConsumer.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "llvm/Support/raw_ostream.h"
#include <set>
namespace swift {
namespace ide {
namespace api {
/// \brief Diagnostic consumer that displays diagnostics to standard output.
class ModuleDifferDiagsConsumer: public PrintingDiagnosticConsumer {
llvm::MapVector<StringRef, std::set<std::string>> AllDiags;
public:
ModuleDifferDiagsConsumer();
~ModuleDifferDiagsConsumer();
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
DiagnosticKind Kind,
StringRef FormatString,
ArrayRef<DiagnosticArgument> FormatArgs,
const DiagnosticInfo &Info) override;
};
}
}
}
#endif

View File

@@ -26,8 +26,11 @@
// can be reflected as source-breaking changes for API users. If they are,
// the output of api-digester will include such changes.
#include "swift/AST/DiagnosticsModuleDiffer.h"
#include "swift/IDE/APIDigesterData.h"
#include <functional>
#include <ModuleAnalyzerNodes.h>
#include "ModuleAnalyzerNodes.h"
#include "ModuleDiagsConsumer.h"
using namespace swift;
using namespace ide;
@@ -1478,16 +1481,6 @@ public:
}
};
// Redefine << so that we can output the name of decl kind.
raw_ostream &operator<<(raw_ostream &Out, const DeclKind Value) {
switch (Value) {
#define DECL(X, PARENT) case DeclKind::X: return Out << #X;
#include "swift/AST/DeclNodes.def"
}
llvm_unreachable("Unhandled DeclKind in switch.");
}
class DiagnosisEmitter : public SDKNodeVisitor {
void handle(const SDKNodeDecl *D, NodeAnnotation Anno);
void visitType(SDKNodeType *T);
@@ -1495,182 +1488,18 @@ class DiagnosisEmitter : public SDKNodeVisitor {
void visit(NodePtr Node) override;
SDKNodeDecl *findAddedDecl(const SDKNodeDecl *Node);
bool findTypeAliasDecl(const SDKNodeDecl *Node);
static StringRef printName(StringRef Name);
static StringRef printDiagKeyword(StringRef Name);
static void collectAddedDecls(NodePtr Root, std::set<SDKNodeDecl*> &Results);
template<typename T>
struct DiagBag {
std::vector<T> Diags;
~DiagBag() {
llvm::outs() << "\n/* ";
T::theme(llvm::outs());
llvm::outs() << " */\n";
removeRedundantAndSort(Diags);
std::for_each(Diags.begin(), Diags.end(), [](T &Diag) {
if (Diag.isABISpecific() && !options::Abi)
return;
Diag.outputModule();
Diag.output();
});
}
};
struct MetaInfo {
StringRef ModuleName;
StringRef HeaderName;
DeclKind Kind;
StringRef Name;
bool IsABISpecific;
MetaInfo(const SDKNodeDecl *Node, bool IsABISpecific):
ModuleName(Node->getModuleName()), HeaderName(Node->getHeaderName()),
Kind(Node->getDeclKind()), Name(Node->getFullyQualifiedName()),
IsABISpecific(IsABISpecific) {}
int compare(MetaInfo &Other) const {
if (ModuleName != Other.ModuleName)
return ModuleName.compare(Other.ModuleName);
if (HeaderName != Other.HeaderName)
return HeaderName.compare(Other.HeaderName);
if (Kind != Other.Kind)
return (uint8_t)Kind - (uint8_t)Other.Kind;
return Name.compare(Other.Name);
}
};
class DiagBase {
protected:
MetaInfo Info;
DiagBase(MetaInfo Info): Info(Info) {}
virtual ~DiagBase() = default;
raw_ostream &outputName() const {
return llvm::outs() << Info.Kind << " " << printName(Info.Name);
}
public:
void outputModule() const {
if (options::PrintModule) {
llvm::outs() << Info.ModuleName;
if (!Info.HeaderName.empty())
llvm::outs() << "(" << Info.HeaderName << ")";
llvm::outs() << ": ";
}
}
virtual void output() const = 0;
bool isABISpecific() const { return Info.IsABISpecific; }
};
struct RemovedDeclDiag: public DiagBase {
DeclKind Kind;
StringRef Name;
bool IsDeprecated;
RemovedDeclDiag(MetaInfo Info, bool IsDeprecated): DiagBase(Info),
IsDeprecated(IsDeprecated) {}
bool operator<(RemovedDeclDiag Other) const {
return Info.compare(Other.Info) < 0;
}
void output() const override;
static void theme(raw_ostream &OS) { OS << "Removed Decls"; };
};
struct MovedDeclDiag: public DiagBase {
DeclKind AddedKind;
StringRef AddedName;
MovedDeclDiag(MetaInfo Info, DeclKind AddedKind, StringRef AddedName):
DiagBase(Info), AddedKind(AddedKind), AddedName(AddedName) {}
bool operator<(MovedDeclDiag Other) const {
return Info.compare(Other.Info) < 0;
}
void output() const override;
static void theme(raw_ostream &OS) { OS << "Moved Decls"; };
};
struct RenamedDeclDiag: public DiagBase {
DeclKind KindAfter;
StringRef NameAfter;
RenamedDeclDiag(MetaInfo Info, DeclKind KindAfter, StringRef NameAfter):
DiagBase(Info), KindAfter(KindAfter), NameAfter(NameAfter) {}
bool operator<(RenamedDeclDiag Other) const {
return Info.compare(Other.Info) < 0;
};
void output() const override;
static void theme(raw_ostream &OS) { OS << "Renamed Decls"; };
};
struct DeclAttrDiag: public DiagBase {
StringRef AttrBefore;
StringRef AttrAfter;
DeclAttrDiag(MetaInfo Info, StringRef AttrBefore, StringRef AttrAfter):
DiagBase(Info), AttrBefore(AttrBefore), AttrAfter(AttrAfter) {}
DeclAttrDiag(MetaInfo Info, StringRef AttrAfter): DeclAttrDiag(Info,
StringRef(), AttrAfter) {}
bool operator<(DeclAttrDiag Other) const;
void output() const override;
static void theme(raw_ostream &OS) { OS << "Decl Attribute changes"; };
};
struct DeclTypeChangeDiag: public DiagBase {
StringRef TypeNameBefore;
StringRef TypeNameAfter;
StringRef Description;
DeclTypeChangeDiag(MetaInfo Info, StringRef TypeNameBefore,
StringRef TypeNameAfter,
StringRef Description): DiagBase(Info),
TypeNameBefore(TypeNameBefore), TypeNameAfter(TypeNameAfter),
Description(Description) {}
bool operator<(DeclTypeChangeDiag Other) const {
return Info.compare(Other.Info) < 0;
};
void output() const override;
static void theme(raw_ostream &OS) { OS << "Type Changes"; };
};
struct RawRepresentableChangeDiag: public DiagBase {
StringRef UnderlyingType;
StringRef RawTypeName;
RawRepresentableChangeDiag(MetaInfo Info, StringRef UnderlyingType,
StringRef RawTypeName): DiagBase(Info), UnderlyingType(UnderlyingType),
RawTypeName(RawTypeName) {}
bool operator<(RawRepresentableChangeDiag Other) const {
return Info.compare(Other.Info) < 0;
}
void output() const override {
outputName() << "(" << UnderlyingType << ")"
<< " is now " << RawTypeName << " representable\n";
}
static void theme(raw_ostream &OS) { OS << "RawRepresentable Changes"; };
};
struct GenericSignatureChangeDiag: public DiagBase {
StringRef GSBefore;
StringRef GSAfter;
GenericSignatureChangeDiag(MetaInfo Info, StringRef GSBefore,
StringRef GSAfter): DiagBase(Info),
GSBefore(GSBefore), GSAfter(GSAfter) {}
bool operator<(GenericSignatureChangeDiag Other) const {
return Info.compare(Other.Info) < 0;
}
void output() const override {
outputName() << " has generic signature change from " << GSBefore << " to "
<< GSAfter << "\n";
}
static void theme(raw_ostream &OS) { OS << "Generic Signature Changes"; };
};
std::set<SDKNodeDecl*> AddedDecls;
DiagBag<DeclAttrDiag> AttrChangedDecls;
DiagBag<DeclTypeChangeDiag> TypeChangedDecls;
DiagBag<RenamedDeclDiag> RenamedDecls;
DiagBag<MovedDeclDiag> MovedDecls;
DiagBag<RemovedDeclDiag> RemovedDecls;
DiagBag<RawRepresentableChangeDiag> RawRepresentableDecls;
DiagBag<GenericSignatureChangeDiag> GSChangeDecls;
UpdatedNodesMap &UpdateMap;
NodeMap &TypeAliasUpdateMap;
TypeMemberDiffVector &MemberChanges;
DiagnosticEngine &Diags;
DiagnosisEmitter(SDKContext &Ctx):
UpdateMap(Ctx.getNodeUpdateMap()),
TypeAliasUpdateMap(Ctx.getTypeAliasUpdateMap()),
MemberChanges(Ctx.getTypeMemberDiffs()){}
MemberChanges(Ctx.getTypeMemberDiffs()), Diags(Ctx.getDiags()) {}
public:
static void diagnosis(NodePtr LeftRoot, NodePtr RightRoot,
@@ -1707,58 +1536,6 @@ bool DiagnosisEmitter::findTypeAliasDecl(const SDKNodeDecl *Node) {
});
}
StringRef DiagnosisEmitter::printName(StringRef Name) {
OSColor Color(llvm::outs(), llvm::raw_ostream::CYAN);
Color << Name;
return StringRef();
}
StringRef DiagnosisEmitter::printDiagKeyword(StringRef Name) {
OSColor Color(llvm::outs(), llvm::raw_ostream::YELLOW);
Color << Name;
return StringRef();
}
void DiagnosisEmitter::RemovedDeclDiag::output() const {
outputName() << " has been " << printDiagKeyword("removed");
if (IsDeprecated)
llvm::outs() << " (deprecated)";
llvm::outs() << "\n";
}
void DiagnosisEmitter::MovedDeclDiag::output() const {
outputName() << " has been " << printDiagKeyword("moved") << " to "
<< AddedKind << " " << printName(AddedName) << "\n";
}
void DiagnosisEmitter::RenamedDeclDiag::output() const {
outputName() << " has been " << printDiagKeyword("renamed") << " to "
<< KindAfter << " " << printName(NameAfter) << "\n";
}
void DiagnosisEmitter::DeclTypeChangeDiag::output() const {
outputName() << " has "
<< Description << " type change from "
<< printName(TypeNameBefore) << " to "
<< printName(TypeNameAfter) << "\n";
}
bool DiagnosisEmitter::DeclAttrDiag::operator<(DeclAttrDiag Other) const {
auto result = Info.compare(Other.Info);
if (result)
return result < 0;
return AttrAfter.compare(Other.AttrAfter) < 0;
}
void DiagnosisEmitter::DeclAttrDiag::output() const {
if (AttrBefore.empty())
outputName() << " is now " << printDiagKeyword(AttrAfter)<< "\n";
else
outputName() << " changes from " << printDiagKeyword(AttrBefore)
<< " to "<< printDiagKeyword(AttrAfter)<< "\n";
}
void DiagnosisEmitter::diagnosis(NodePtr LeftRoot, NodePtr RightRoot,
SDKContext &Ctx) {
DiagnosisEmitter Emitter(Ctx);
@@ -1771,16 +1548,15 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
auto &Ctx = Node->getSDKContext();
switch(Anno) {
case NodeAnnotation::Removed: {
MetaInfo ScreenInfo(Node, false);
// If we can find a type alias decl with the same name of this type, we
// consider the type is not removed.
if (findTypeAliasDecl(Node))
return;
if (auto *Added = findAddedDecl(Node)) {
if (Node->getDeclKind() != DeclKind::Constructor) {
MovedDecls.Diags.emplace_back(ScreenInfo,
Added->getDeclKind(),
Added->getFullyQualifiedName());
Diags.diagnose(diag::moved_decl, Node->getScreenInfo(),
Ctx.buffer((Twine(getDeclKindStr(Added->getDeclKind())) + " " +
Added->getFullyQualifiedName()).str()));
return;
}
}
@@ -1790,8 +1566,9 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
auto It = std::find_if(MemberChanges.begin(), MemberChanges.end(),
[&](TypeMemberDiffItem &Item) { return Item.usr == Node->getUsr(); });
if (It != MemberChanges.end()) {
RenamedDecls.Diags.emplace_back(ScreenInfo, Node->getDeclKind(),
Ctx.buffer((Twine(It->newTypeName) + "." + It->newPrintedName).str()));
Diags.diagnose(diag::renamed_decl, Node->getScreenInfo(),
Ctx.buffer((Twine(getDeclKindStr(Node->getDeclKind())) + " " +
It->newTypeName + "." + It->newPrintedName).str()));
return;
}
@@ -1800,7 +1577,7 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
// refine diagnostics message instead of showing the type alias has been
// removed.
if (TypeAliasUpdateMap.find((SDKNode*)Node) != TypeAliasUpdateMap.end()) {
RawRepresentableDecls.Diags.emplace_back(ScreenInfo,
Diags.diagnose(diag::raw_type_change, Node->getScreenInfo(),
Node->getAs<SDKNodeDeclTypeAlias>()->getUnderlyingType()->getPrintedName(),
TypeAliasUpdateMap[(SDKNode*)Node]->getAs<SDKNodeDeclType>()->
getRawValueType()->getPrintedName());
@@ -1822,53 +1599,47 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
}
if (FoundInSuperclass)
return;
RemovedDecls.Diags.emplace_back(ScreenInfo,
Node->isDeprecated());
Diags.diagnose(diag::removed_decl, Node->getScreenInfo(), Node->isDeprecated());
return;
}
case NodeAnnotation::Rename: {
MetaInfo ScreenInfo(Node, false);
auto *Count = UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeDecl>();
RenamedDecls.Diags.emplace_back(ScreenInfo,
Count->getDeclKind(),
Count->getFullyQualifiedName());
Diags.diagnose(diag::renamed_decl, Node->getScreenInfo(),
Ctx.buffer((Twine(getDeclKindStr(Count->getDeclKind())) + " " +
Count->getFullyQualifiedName()).str()));
return;
}
case NodeAnnotation::NowMutating: {
MetaInfo ScreenInfo(Node, false);
AttrChangedDecls.Diags.emplace_back(ScreenInfo, Ctx.buffer("mutating"));
Diags.diagnose(diag::decl_new_attr, Node->getScreenInfo(),
Ctx.buffer("mutating"));
return;
}
case NodeAnnotation::NowThrowing: {
MetaInfo ScreenInfo(Node, false);
AttrChangedDecls.Diags.emplace_back(ScreenInfo, Ctx.buffer("throwing"));
Diags.diagnose(diag::decl_new_attr, Node->getScreenInfo(),
Ctx.buffer("throwing"));
return;
}
case NodeAnnotation::StaticChange: {
MetaInfo ScreenInfo(Node, false);
AttrChangedDecls.Diags.emplace_back(ScreenInfo,
Diags.diagnose(diag::decl_new_attr, Node->getScreenInfo(),
Ctx.buffer(Node->isStatic() ? "not static" : "static"));
return;
}
case NodeAnnotation::OwnershipChange: {
MetaInfo ScreenInfo(Node, false);
auto getOwnershipDescription = [&](swift::ReferenceOwnership O) {
if (O == ReferenceOwnership::Strong)
return Ctx.buffer("strong");
return keywordOf(O);
};
auto *Count = UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeDecl>();
AttrChangedDecls.Diags.emplace_back(
ScreenInfo,
Diags.diagnose(diag::decl_attr_change, Node->getScreenInfo(),
getOwnershipDescription(Node->getReferenceOwnership()),
getOwnershipDescription(Count->getReferenceOwnership()));
return;
}
case NodeAnnotation::ChangeGenericSignature: {
MetaInfo ScreenInfo(Node, false);
GSChangeDecls.Diags.emplace_back(ScreenInfo, Node->getGenericSignature(),
UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeDecl>()->
getGenericSignature());
Diags.diagnose(diag::generic_sig_change, Node->getScreenInfo(),
Node->getGenericSignature(), UpdateMap.findUpdateCounterpart(Node)->
getAs<SDKNodeDecl>()->getGenericSignature());
return;
}
@@ -1879,11 +1650,11 @@ void DiagnosisEmitter::handle(const SDKNodeDecl *Node, NodeAnnotation Anno) {
[&](const ABIAttributeInfo &I) { return I.Annotation == Anno; });
if (It == Infos.end())
return;
MetaInfo ScreenInfo(Node, true);
auto Desc = Node->hasDeclAttribute(It->Kind) ?
Ctx.buffer((llvm::Twine("without ") + It->Content).str()):
Ctx.buffer((llvm::Twine("with ") + It->Content).str());
AttrChangedDecls.Diags.emplace_back(ScreenInfo, Desc);
if (options::Abi)
Diags.diagnose(diag::decl_new_attr, Node->getScreenInfo(), Desc);
return;
}
}
@@ -1901,7 +1672,6 @@ void DiagnosisEmitter::visitType(SDKNodeType *Node) {
auto *Parent = dyn_cast<SDKNodeDecl>(Node->getParent());
if (!Parent || Parent->isSDKPrivate())
return;
MetaInfo ScreenInfo(Parent, false);
SDKContext &Ctx = Node->getSDKContext();
if (Node->isAnnotatedAs(NodeAnnotation::Updated)) {
auto *Count = UpdateMap.findUpdateCounterpart(Node)->getAs<SDKNodeType>();
@@ -1914,10 +1684,8 @@ void DiagnosisEmitter::visitType(SDKNodeType *Node) {
SDKNodeDeclAbstractFunc::getTypeRoleDescription(Ctx, Parent->getChildIndex(Node)) :
Ctx.buffer("declared");
if (Node->getPrintedName() != Count->getPrintedName())
TypeChangedDecls.Diags.emplace_back(ScreenInfo,
Node->getPrintedName(),
Count->getPrintedName(),
Descriptor);
Diags.diagnose(diag::decl_type_change, Parent->getScreenInfo(),
Descriptor, Node->getPrintedName(), Count->getPrintedName());
break;
default:
break;
@@ -2043,7 +1811,7 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath,
llvm::errs() << RightPath << " does not exist\n";
return 1;
}
PrintingDiagnosticConsumer PDC;
ModuleDifferDiagsConsumer PDC;
SDKContext Ctx(Opts);
Ctx.getDiags().addConsumer(PDC);
@@ -2061,6 +1829,7 @@ static int diagnoseModuleChange(StringRef LeftPath, StringRef RightPath,
RefinementPass.pass(LeftModule, RightModule);
// Find member hoist changes to help refine diagnostics.
findTypeMemberDiffs(LeftModule, RightModule, Ctx.getTypeMemberDiffs());
DiagnosisEmitter::diagnosis(LeftModule, RightModule, Ctx);
return 0;
}
@@ -2099,7 +1868,7 @@ static int compareSDKs(StringRef LeftPath, StringRef RightPath,
}
llvm::errs() << "Diffing: " << LeftPath << " and " << RightPath << "\n";
PrintingDiagnosticConsumer PDC;
ModuleDifferDiagsConsumer PDC;
SDKContext Ctx(Opts);
Ctx.getDiags().addConsumer(PDC);
@@ -2319,6 +2088,7 @@ static CheckerOptions getCheckOpts() {
Opts.Verbose = options::Verbose;
Opts.AbortOnModuleLoadFailure = options::AbortOnModuleLoadFailure;
Opts.LocationFilter = options::LocationFilter;
Opts.PrintModule = options::PrintModule;
return Opts;
}