Skip to content

[WIP] Improve ClangImporter Diagnostics #39923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 4, 2022
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
3 changes: 3 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,9 @@ class ASTContext final {
InheritedProtocolConformance *
getInheritedConformance(Type type, ProtocolConformance *inherited);

/// Check if \p decl is included in LazyContexts.
bool isLazyContext(const DeclContext *decl);

/// Get the lazy data for the given declaration.
///
/// \param lazyLoader If non-null, the lazy loader to use when creating the
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/ClangModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ class ClangModuleLoader : public ModuleLoader {
/// Imports a clang decl directly, rather than looking up its name.
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;

/// Emits any import diagnostics associated with the provided decl.
virtual void diagnoseDeclDirectly(const clang::NamedDecl *decl) = 0;

/// Instantiate and import class template using given arguments.
///
/// This method will find the clang::ClassTemplateSpecialization decl if
Expand Down
38 changes: 27 additions & 11 deletions include/swift/AST/DiagnosticEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/VersionTuple.h"

namespace clang {
class NamedDecl;
}

namespace swift {
class Decl;
class DeclAttribute;
Expand Down Expand Up @@ -116,7 +120,8 @@ namespace swift {
VersionTuple,
LayoutConstraint,
ActorIsolation,
Diagnostic
Diagnostic,
ClangDecl
};

namespace diag {
Expand Down Expand Up @@ -149,6 +154,7 @@ namespace swift {
LayoutConstraint LayoutConstraintVal;
ActorIsolation ActorIsolationVal;
DiagnosticInfo *DiagnosticVal;
const clang::NamedDecl *ClangDecl;
};

public:
Expand Down Expand Up @@ -251,6 +257,9 @@ namespace swift {
DiagnosticVal(D) {
}

DiagnosticArgument(const clang::NamedDecl *ND)
: Kind(DiagnosticArgumentKind::ClangDecl), ClangDecl(ND) {}

/// Initializes a diagnostic argument using the underlying type of the
/// given enum.
template<
Expand Down Expand Up @@ -356,6 +365,11 @@ namespace swift {
assert(Kind == DiagnosticArgumentKind::Diagnostic);
return DiagnosticVal;
}

const clang::NamedDecl *getAsClangDecl() const {
assert(Kind == DiagnosticArgumentKind::ClangDecl);
return ClangDecl;
}
};

/// Describes the current behavior to take with a diagnostic.
Expand Down Expand Up @@ -1327,18 +1341,20 @@ namespace swift {
builder();
}

/// Temporary on-stack storage and unescaping for encoded diagnostic
/// messages.
class EncodedDiagnosticMessage {
llvm::SmallString<128> Buf;
void printClangDeclName(const clang::NamedDecl *ND, llvm::raw_ostream &os);

public:
/// \param S A string with an encoded message
EncodedDiagnosticMessage(StringRef S);
/// Temporary on-stack storage and unescaping for encoded diagnostic
/// messages.
class EncodedDiagnosticMessage {
llvm::SmallString<128> Buf;

/// The unescaped message to display to the user.
const StringRef Message;
};
public:
/// \param S A string with an encoded message
EncodedDiagnosticMessage(StringRef S);

/// The unescaped message to display to the user.
const StringRef Message;
};

/// Returns a value that can be used to select between accessor kinds in
/// diagnostics.
Expand Down
25 changes: 25 additions & 0 deletions include/swift/AST/DiagnosticsClangImporter.def
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,30 @@ WARNING(import_multiple_mainactor_attr,none,

ERROR(module_map_not_found, none, "module map file '%0' not found", (StringRef))

NOTE(macro_not_imported_unsupported_operator, none, "operator not supported in macro arithmetic", ())
NOTE(macro_not_imported_unsupported_named_operator, none, "operator '%0' not supported in macro arithmetic", (StringRef))
NOTE(macro_not_imported_invalid_string_literal, none, "invalid string literal", ())
NOTE(macro_not_imported_invalid_numeric_literal, none, "invalid numeric literal", ())
NOTE(macro_not_imported_unsupported_literal, none, "only numeric and string macro literals supported", ())
NOTE(macro_not_imported_nested_cast, none, "non-null nested casts not supported", ())

ERROR(macro_not_imported_function_like, none, "macro '%0' not imported: function like macros not supported", (StringRef))
ERROR(macro_not_imported_unsupported_structure, none, "macro '%0' not imported: structure not supported", (StringRef))
ERROR(macro_not_imported, none, "macro '%0' not imported", (StringRef))

NOTE(return_type_not_imported, none, "return type not imported", ())
NOTE(parameter_type_not_imported, none, "parameter %0 not imported", (const clang::NamedDecl*))
NOTE(incomplete_interface, none, "interface %0 is incomplete", (const clang::NamedDecl*))
NOTE(incomplete_protocol, none, "protocol %0 is incomplete", (const clang::NamedDecl*))
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))

WARNING(record_field_not_imported, none, "field %0 not imported", (const clang::NamedDecl*))
WARNING(invoked_func_not_imported, none, "function %0 not imported", (const clang::NamedDecl*))
WARNING(record_method_not_imported, none, "method %0 not imported", (const clang::NamedDecl*))
WARNING(objc_property_not_imported, none, "property %0 not imported", (const clang::NamedDecl*))

NOTE(forward_declared_interface_label, none, "interface %0 forward declared here", (const clang::NamedDecl*))
NOTE(forward_declared_protocol_label, none, "protocol %0 forward declared here", (const clang::NamedDecl*))

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
3 changes: 3 additions & 0 deletions include/swift/AST/LazyResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ class alignas(void*) LazyMemberLoader {
loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N,
uint64_t contextData) = 0;

virtual void diagnoseMissingNamedMember(const IterableDeclContext *IDC,
DeclName name) = 0;

/// Populates the given vector with all conformances for \p D.
///
/// The implementation should \em not call setConformances on \p D.
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,12 @@ namespace swift {
/// Enable experimental flow-sensitive concurrent captures.
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;

/// Enable experimental ClangImporter diagnostics.
bool EnableExperimentalClangImporterDiagnostics = false;

/// Enable experimental eager Clang module diagnostics.
bool EnableExperimentalEagerClangModuleDiagnostics = false;

/// Enable inference of Sendable conformances for public types.
bool EnableInferPublicSendable = false;

Expand Down
9 changes: 9 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace clang {
class EnumDecl;
class MacroInfo;
class Module;
class ModuleMacro;
class NamedDecl;
class Sema;
class TargetInfo;
Expand Down Expand Up @@ -109,6 +110,11 @@ class DWARFImporterDelegate {
virtual void anchor();
};

typedef llvm::PointerUnion<const clang::Decl *, const clang::MacroInfo *,
const clang::ModuleMacro *, const clang::Type *,
const clang::Token *>
ImportDiagnosticTarget;

/// Class that imports Clang modules into Swift, mapping directly
/// from Clang ASTs over to Swift ASTs.
class ClangImporter final : public ClangModuleLoader {
Expand Down Expand Up @@ -509,6 +515,9 @@ class ClangImporter final : public ClangModuleLoader {

/// Imports a clang decl directly, rather than looking up it's name.
Decl *importDeclDirectly(const clang::NamedDecl *decl) override;

/// Emits any pending diagnostics associated with the provided decl.
void diagnoseDeclDirectly(const clang::NamedDecl *decl) override;
};

ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,14 @@ def enable_experimental_flow_sensitive_concurrent_captures :
Flag<["-"], "enable-experimental-flow-sensitive-concurrent-captures">,
HelpText<"Enable flow-sensitive concurrent captures">;

def enable_experimental_clang_importer_diagnostics :
Flag<["-"], "enable-experimental-clang-importer-diagnostics">,
HelpText<"Enable experimental diagnostics when importing C, C++, and Objective-C libraries">;

def enable_experimental_eager_clang_module_diagnostics :
Flag<["-"], "enable-experimental-eager-clang-module-diagnostics">,
HelpText<"Enable experimental eager diagnostics reporting on the importability of all referenced C, C++, and Objective-C libraries">;

def enable_resilience : Flag<["-"], "enable-resilience">,
HelpText<"Deprecated, use -enable-library-evolution instead">;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2462,6 +2462,10 @@ ASTContext::getInheritedConformance(Type type, ProtocolConformance *inherited) {
return result;
}

bool ASTContext::isLazyContext(const DeclContext *dc) {
return getImpl().LazyContexts.count(dc) != 0;
}

LazyContextData *ASTContext::getOrCreateLazyContextData(
const DeclContext *dc,
LazyMemberLoader *lazyLoader) {
Expand Down
16 changes: 15 additions & 1 deletion lib/AST/DiagnosticEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
//===----------------------------------------------------------------------===//

#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsCommon.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticSuppression.h"
#include "swift/AST/DiagnosticsCommon.h"
#include "swift/AST/Module.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/PrintOptions.h"
Expand All @@ -30,6 +30,8 @@
#include "swift/Config.h"
#include "swift/Localization/LocalizationFormat.h"
#include "swift/Parse/Lexer.h" // bad dependency
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
Expand Down Expand Up @@ -566,6 +568,11 @@ static bool isMainActor(Type type) {
return false;
}

void swift::printClangDeclName(const clang::NamedDecl *ND,
llvm::raw_ostream &os) {
ND->getNameForDiagnostic(os, ND->getASTContext().getPrintingPolicy(), false);
}

/// Format a single diagnostic argument and write it to the given
/// stream.
static void formatDiagnosticArgument(StringRef Modifier,
Expand Down Expand Up @@ -832,6 +839,13 @@ static void formatDiagnosticArgument(StringRef Modifier,
diagArg->FormatArgs);
break;
}

case DiagnosticArgumentKind::ClangDecl:
assert(Modifier.empty() && "Improper modifier for ClangDecl argument");
Out << FormatOpts.OpeningQuotationMark;
printClangDeclName(Arg.getAsClangDecl(), Out);
Out << FormatOpts.ClosingQuotationMark;
break;
}
}

Expand Down
12 changes: 11 additions & 1 deletion lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1494,12 +1494,22 @@ DirectLookupRequest::evaluate(Evaluator &evaluator,
populateLookupTableEntryFromExtensions(ctx, Table, baseName, decl);
}

Table.markLazilyComplete(name.getBaseName());
Table.markLazilyComplete(baseName);
}

// Look for a declaration with this name.
auto known = Table.find(name);
if (known == Table.end()) {
// Diagnose the missing member if:
// - The flag enabling ClangImporter diagnostics is passed.
// - The containing decl is a ClangDecl.
// - The containing decl (and DeclContext) is lazy.
if (ctx.LangOpts.EnableExperimentalClangImporterDiagnostics &&
ctx.isLazyContext(decl) && decl->getDecl()->getClangDecl()) {
auto ci =
ctx.getOrCreateLazyIterableContextData(decl, /*lazyLoader=*/nullptr);
ci->loader->diagnoseMissingNamedMember(decl, name);
}
return TinyPtrVector<ValueDecl *>();
}

Expand Down
Loading