Skip to content

[Sema] Add logic to diagnose regex feature availability #77248

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 2 commits into from
Oct 29, 2024
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
68 changes: 68 additions & 0 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@

SWIFT_BEGIN_NULLABILITY_ANNOTATIONS

namespace llvm {
template<typename T> class ArrayRef;
}

namespace swift {
class Argument;
class ASTContext;
Expand All @@ -42,6 +46,8 @@ class Identifier;
class IfConfigClauseRangeInfo;
struct LabeledStmtInfo;
class ProtocolConformanceRef;
class RegexLiteralPatternFeature;
class RegexLiteralPatternFeatureKind;
class Type;
class CanType;
class TypeBase;
Expand Down Expand Up @@ -1351,6 +1357,68 @@ BridgedPrefixUnaryExpr
BridgedPrefixUnaryExpr_createParsed(BridgedASTContext cContext,
BridgedExpr oper, BridgedExpr operand);

class BridgedRegexLiteralPatternFeatureKind final {
unsigned RawValue;

public:
BRIDGED_INLINE
SWIFT_NAME("init(rawValue:)")
BridgedRegexLiteralPatternFeatureKind(SwiftInt rawValue);

using UnbridgedTy = swift::RegexLiteralPatternFeatureKind;

BRIDGED_INLINE
BridgedRegexLiteralPatternFeatureKind(UnbridgedTy kind);

BRIDGED_INLINE
UnbridgedTy unbridged() const;
};

class BridgedRegexLiteralPatternFeature final {
BridgedCharSourceRange Range;
BridgedRegexLiteralPatternFeatureKind Kind;

public:
SWIFT_NAME("init(kind:at:)")
BridgedRegexLiteralPatternFeature(BridgedRegexLiteralPatternFeatureKind kind,
BridgedCharSourceRange range)
: Range(range), Kind(kind) {}

using UnbridgedTy = swift::RegexLiteralPatternFeature;

BRIDGED_INLINE
BridgedRegexLiteralPatternFeature(UnbridgedTy feature);

BRIDGED_INLINE
UnbridgedTy unbridged() const;
};

class BridgedRegexLiteralPatternFeatures final {
BridgedRegexLiteralPatternFeature *_Nullable Data;
SwiftInt Count;

public:
BridgedRegexLiteralPatternFeatures() : Data(nullptr), Count(0) {}

SWIFT_NAME("init(baseAddress:count:)")
BridgedRegexLiteralPatternFeatures(
BridgedRegexLiteralPatternFeature *_Nullable data, SwiftInt count)
: Data(data), Count(count) {}

using UnbridgedTy = llvm::ArrayRef<BridgedRegexLiteralPatternFeature>;

BRIDGED_INLINE
UnbridgedTy unbridged() const;

SWIFT_IMPORT_UNSAFE
BridgedRegexLiteralPatternFeature *_Nullable getData() const {
return Data;
}
SwiftInt getCount() const {
return Count;
}
};

SWIFT_NAME("BridgedRegexLiteralExpr.createParsed(_:loc:regexText:)")
BridgedRegexLiteralExpr
BridgedRegexLiteralExpr_createParsed(BridgedASTContext cContext,
Expand Down
36 changes: 36 additions & 0 deletions include/swift/AST/ASTBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/ArgumentList.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/IfConfigClauseRangeInfo.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/ProtocolConformanceRef.h"
#include "swift/Basic/Assertions.h"

SWIFT_BEGIN_NULLABILITY_ANNOTATIONS

Expand Down Expand Up @@ -379,6 +381,40 @@ swift::IfConfigClauseRangeInfo BridgedIfConfigClauseRangeInfo::unbridged() const
clauseKind);
}

//===----------------------------------------------------------------------===//
// MARK: BridgedRegexLiteralPatternFeature
//===----------------------------------------------------------------------===//

BridgedRegexLiteralPatternFeatureKind::BridgedRegexLiteralPatternFeatureKind(
SwiftInt rawValue)
: RawValue(rawValue) {
ASSERT(rawValue >= 0);
ASSERT(rawValue == RawValue);
}

BridgedRegexLiteralPatternFeatureKind::BridgedRegexLiteralPatternFeatureKind(
UnbridgedTy kind)
: RawValue(kind.getRawValue()) {}

BridgedRegexLiteralPatternFeatureKind::UnbridgedTy
BridgedRegexLiteralPatternFeatureKind::unbridged() const {
return UnbridgedTy(RawValue);
}

BridgedRegexLiteralPatternFeature::BridgedRegexLiteralPatternFeature(
UnbridgedTy feature)
: Range(feature.getRange()), Kind(feature.getKind()) {}

BridgedRegexLiteralPatternFeature::UnbridgedTy
BridgedRegexLiteralPatternFeature::unbridged() const {
return UnbridgedTy(Kind.unbridged(), Range.unbridged());
}

BridgedRegexLiteralPatternFeatures::UnbridgedTy
BridgedRegexLiteralPatternFeatures::unbridged() const {
return UnbridgedTy(Data, Count);
}

//===----------------------------------------------------------------------===//
// MARK: BridgedStmtConditionElement
//===----------------------------------------------------------------------===//
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,9 @@ namespace swift {
/// Add a character-based range to the currently-active diagnostic.
InFlightDiagnostic &highlightChars(SourceLoc Start, SourceLoc End);

/// Add a character-based range to the currently-active diagnostic.
InFlightDiagnostic &highlightChars(CharSourceRange Range);

static const char *fixItStringFor(const FixItID id);

/// Get the best location where an 'import' fixit might be offered.
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -5962,6 +5962,10 @@ ERROR(regex_capture_types_failed_to_decode,none,
"failed to decode capture types for regular expression literal; this may "
"be a compiler bug", ())

ERROR(regex_feature_unavailable, none,
"%0 is only available in %1 %2 or newer",
(StringRef, StringRef, llvm::VersionTuple))

ERROR(must_import_regex_builder_module,none,
"regex builder requires the 'RegexBuilder' module be imported'", ())

Expand Down
47 changes: 47 additions & 0 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,50 @@ class InterpolatedStringLiteralExpr : public LiteralExpr {
}
};

/// The opaque kind of a RegexLiteralExpr feature, which should only be
/// interpreted by the compiler's regex parsing library.
class RegexLiteralPatternFeatureKind final {
unsigned RawValue;

public:
RegexLiteralPatternFeatureKind(unsigned rawValue) : RawValue(rawValue) {}

unsigned getRawValue() const { return RawValue; }

AvailabilityRange getAvailability(ASTContext &ctx) const;
StringRef getDescription(ASTContext &ctx) const;

friend llvm::hash_code
hash_value(const RegexLiteralPatternFeatureKind &kind) {
return llvm::hash_value(kind.getRawValue());
}

friend bool operator==(const RegexLiteralPatternFeatureKind &lhs,
const RegexLiteralPatternFeatureKind &rhs) {
return lhs.getRawValue() == rhs.getRawValue();
}

friend bool operator!=(const RegexLiteralPatternFeatureKind &lhs,
const RegexLiteralPatternFeatureKind &rhs) {
return !(lhs == rhs);
}
};

/// A specific feature used in a RegexLiteralExpr, needed for availability
/// diagnostics.
class RegexLiteralPatternFeature final {
RegexLiteralPatternFeatureKind Kind;
CharSourceRange Range;

public:
RegexLiteralPatternFeature(RegexLiteralPatternFeatureKind kind,
CharSourceRange range)
: Kind(kind), Range(range) {}

RegexLiteralPatternFeatureKind getKind() const { return Kind; }
CharSourceRange getRange() const { return Range; }
};

/// A regular expression literal e.g '(a|c)*'.
class RegexLiteralExpr : public LiteralExpr {
ASTContext *Ctx;
Expand Down Expand Up @@ -1021,6 +1065,9 @@ class RegexLiteralExpr : public LiteralExpr {
/// Retrieve the version of the regex string.
unsigned getVersion() const;

/// Retrieve any features used in the regex pattern.
ArrayRef<RegexLiteralPatternFeature> getPatternFeatures() const;

SourceRange getSourceRange() const { return Loc; }

static bool classof(const Expr *E) {
Expand Down
42 changes: 42 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -5110,6 +5110,7 @@ struct RegexLiteralPatternInfo {
StringRef RegexToEmit;
Type RegexType;
size_t Version;
ArrayRef<RegexLiteralPatternFeature> Features;
};

/// Parses the regex pattern for a given regex literal using the
Expand All @@ -5131,6 +5132,47 @@ class RegexLiteralPatternInfoRequest
bool isCached() const { return true; }
};

/// The description for a given regex pattern feature. This is cached since
/// the resulting string is allocated in the ASTContext for ease of bridging.
class RegexLiteralFeatureDescriptionRequest
: public SimpleRequest<RegexLiteralFeatureDescriptionRequest,
StringRef(RegexLiteralPatternFeatureKind,
ASTContext *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

StringRef evaluate(Evaluator &evaluator, RegexLiteralPatternFeatureKind kind,
ASTContext *ctx) const;

public:
bool isCached() const { return true; }
};

/// The availability range for a given regex pattern feature.
class RegexLiteralFeatureAvailabilityRequest
: public SimpleRequest<RegexLiteralFeatureAvailabilityRequest,
AvailabilityRange(RegexLiteralPatternFeatureKind,
ASTContext *),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

AvailabilityRange evaluate(Evaluator &evaluator,
RegexLiteralPatternFeatureKind kind,
ASTContext *ctx) const;
};

void simple_display(llvm::raw_ostream &out,
RegexLiteralPatternFeatureKind kind);
SourceLoc extractNearestSourceLoc(RegexLiteralPatternFeatureKind kind);

class IsUnsafeRequest
: public SimpleRequest<IsUnsafeRequest,
bool(Decl *decl),
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,12 @@ SWIFT_REQUEST(TypeChecker, SuppressesConformanceRequest,
SWIFT_REQUEST(TypeChecker, RegexLiteralPatternInfoRequest,
RegexLiteralPatternInfo(const RegexLiteralExpr *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, RegexLiteralFeatureDescriptionRequest,
StringRef(RegexLiteralPatternFeatureKind, ASTContext *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, RegexLiteralFeatureAvailabilityRequest,
AvailabilityRange(RegexLiteralPatternFeatureKind, ASTContext *),
Uncached, NoLocationInfo)

SWIFT_REQUEST(TypeChecker, CaptureInfoRequest,
CaptureInfo(AbstractFunctionDecl *),
Expand Down
19 changes: 19 additions & 0 deletions include/swift/Basic/BasicBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,25 @@ class BridgedCharSourceRangeVector {
#endif
};

//===----------------------------------------------------------------------===//
// MARK: BridgedSwiftVersion
//===----------------------------------------------------------------------===//

class BridgedSwiftVersion {
unsigned Major;
unsigned Minor;

public:
BridgedSwiftVersion() : Major(0), Minor(0) {}

BRIDGED_INLINE
SWIFT_NAME("init(major:minor:)")
BridgedSwiftVersion(SwiftInt major, SwiftInt minor);

unsigned getMajor() const { return Major; }
unsigned getMinor() const { return Minor; }
};

SWIFT_END_NULLABILITY_ANNOTATIONS

#ifndef PURE_BRIDGING_MODE
Expand Down
12 changes: 12 additions & 0 deletions include/swift/Basic/BasicBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#ifndef SWIFT_BASIC_BASICBRIDGINGIMPL_H
#define SWIFT_BASIC_BASICBRIDGINGIMPL_H

#include "swift/Basic/Assertions.h"

SWIFT_BEGIN_NULLABILITY_ANNOTATIONS

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -123,6 +125,16 @@ swift::CharSourceRange BridgedCharSourceRange::unbridged() const {
return swift::CharSourceRange(Start.unbridged(), ByteLength);
}

//===----------------------------------------------------------------------===//
// MARK: BridgedSwiftVersion
//===----------------------------------------------------------------------===//

BridgedSwiftVersion::BridgedSwiftVersion(SwiftInt major, SwiftInt minor)
: Major(major), Minor(minor) {
ASSERT(major >= 0 && minor >= 0);
ASSERT(major == Major && minor == Minor);
}

SWIFT_END_NULLABILITY_ANNOTATIONS

#endif // SWIFT_BASIC_BASICBRIDGINGIMPL_H
22 changes: 16 additions & 6 deletions include/swift/Bridging/ASTGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,22 @@ bool swift_ASTGen_lexRegexLiteral(const char *_Nonnull *_Nonnull curPtrPtr,
bool mustBeRegex,
BridgedNullableDiagnosticEngine diagEngine);

bool swift_ASTGen_parseRegexLiteral(BridgedStringRef inputPtr,
size_t *_Nonnull versionOut,
void *_Nonnull UnsafeMutableRawPointer,
size_t captureStructureSize,
BridgedSourceLoc diagLoc,
BridgedDiagnosticEngine diagEngine);
bool swift_ASTGen_parseRegexLiteral(
BridgedStringRef inputPtr, size_t *_Nonnull versionOut,
void *_Nonnull UnsafeMutableRawPointer, size_t captureStructureSize,
BridgedRegexLiteralPatternFeatures *_Nonnull featuresOut,
BridgedSourceLoc diagLoc, BridgedDiagnosticEngine diagEngine);

void swift_ASTGen_freeBridgedRegexLiteralPatternFeatures(
BridgedRegexLiteralPatternFeatures features);

void swift_ASTGen_getSwiftVersionForRegexPatternFeature(
BridgedRegexLiteralPatternFeatureKind kind,
BridgedSwiftVersion *_Nonnull versionOut);

void swift_ASTGen_getDescriptionForRegexPatternFeature(
BridgedRegexLiteralPatternFeatureKind kind, BridgedASTContext astContext,
BridgedStringRef *_Nonnull descriptionOut);

intptr_t swift_ASTGen_configuredRegions(
BridgedASTContext astContext,
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/DiagnosticEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,13 @@ InFlightDiagnostic &InFlightDiagnostic::highlightChars(SourceLoc Start,
return *this;
}

InFlightDiagnostic &InFlightDiagnostic::highlightChars(CharSourceRange Range) {
assert(IsActive && "Cannot modify an inactive diagnostic");
if (Engine && Range.getStart().isValid())
Engine->getActiveDiagnostic().addRange(Range);
return *this;
}

/// Add an insertion fix-it to the currently-active diagnostic. The
/// text is inserted immediately *after* the token specified.
///
Expand Down
Loading