integrated-application-development / integrated-application-development/sonar-delphi

Support operator overloads implemented by `&&op_*` class functions

Open
#103 0 comments 0 reactions 0 assignees View on GitHub
engine enhancement
Dominant language
Java
Stars
159
Forks
31
Avg merge
5d 4h
Merged PRs (30d)
4

Description

### Prerequisites

- [X] This improvement has not already been suggested.
- [X] This improvement would be generally useful, not specific to my code or setup.

### Engine area

Delphi language support

### Improvement description

#### Background

This is an undocumented implementation detail of the Delphi compiler.

Class operators are compiled to internal class functions, prefixed with a double-ampersand and internal operator name.
It's possible to manually implement these class functions, circumventing the ordinary rules around class overloads.

If you're feeling particularly clever, this lets you implement operator overloads in places where they're not ordinarily allowed (like class helpers and record helpers).

#### Identifying internal names

We can find all of the internal operator names by emitting C++ builder headers for a Delphi record with operator overloads defined.

Given Delphi record `TFoo`:
```pas
type
TFoo = record
private
FValue: Integer;

public
constructor Create(AValue: Integer);

class operator Implicit(AValue: Integer): TFoo;
class operator Explicit(AValue: Integer): TFoo;
class operator Negative(const A: TFoo): TFoo;
class operator Positive(const A: TFoo): TFoo;
class operator LogicalNot(const A: TFoo): TFoo;
class operator Inc(const A: TFoo): TFoo;
class operator Dec(const A: TFoo): TFoo;
class operator Trunc(const A: TFoo): TFoo;
class operator Round(const A: TFoo): TFoo;
class operator In(const A: Integer; const B: TFoo): Boolean;
class operator Equal(const A, B: TFoo): Boolean;
class operator NotEqual(const A, B: TFoo): Boolean;
class operator GreaterThan(const A, B: TFoo): Boolean;
class operator GreaterThanOrEqual(const A, B: TFoo): Boolean;
class operator LessThan(const A, B: TFoo): Boolean;
class operator LessThanOrEqual(const A, B: TFoo): Boolean;
class operator Add(const A, B: TFoo): TFoo;
class operator Subtract(const A, B: TFoo): TFoo;
class operator Multiply(const A, B: TFoo): TFoo;
class operator Divide(const A, B: TFoo): TFoo;
class operator IntDivide(const A, B: TFoo): TFoo;
class operator Modulus(const A, B: TFoo): TFoo;
class operator LeftShift(const A, B: TFoo): TFoo;
class operator RightShift(const A, B: TFoo): TFoo;
class operator LogicalAnd(const A, B: TFoo): TFoo;
class operator LogicalOr(const A, B: TFoo): TFoo;
class operator LogicalXor(const A, B: TFoo): TFoo;
class operator BitwiseAnd(const A, B: TFoo): TFoo;
class operator BitwiseOr(const A, B: TFoo): TFoo;
class operator BitwiseXor(const A, B: TFoo): TFoo;
class operator Assign(var Dest: TFoo; var Src: TFoo);
class operator Include(const A, B: TFoo): TFoo;
class operator Exclude(const A, B: TFoo): TFoo;
class operator True(const Src: TFoo): Boolean;
class operator False(const Src: TFoo): Boolean;
class operator OnesComplement(const Src: TFoo): TFoo;

property Value: Integer read FValue;
end;
```

The following C++ type is emitted:
```hpp
struct DECLSPEC_DRECORD TFoo
{
private:
int FValue;

public:
__fastcall TFoo(int AValue);
static TFoo __fastcall _op_Implicit(int AValue);
static TFoo __fastcall _op_Explicit(int AValue);
static TFoo __fastcall _op_UnaryNegation(const TFoo A);
static TFoo __fastcall _op_UnaryPlus(const TFoo A);
static TFoo __fastcall _op_LogicalNot(const TFoo A);
static TFoo __fastcall _op_Increment(const TFoo A);
static TFoo __fastcall _op_Decrement(const TFoo A);
static TFoo __fastcall _op_Trunc(const TFoo A);
static TFoo __fastcall _op_Round(const TFoo A);
static bool __fastcall _op_In(const int A, const TFoo B);
static bool __fastcall _op_Equality(const TFoo A, const TFoo B);
static bool __fastcall _op_Inequality(const TFoo A, const TFoo B);
static bool __fastcall _op_GreaterThan(const TFoo A, const TFoo B);
static bool __fastcall _op_GreaterThanOrEqual(const TFoo A, const TFoo B);
static bool __fastcall _op_LessThan(const TFoo A, const TFoo B);
static bool __fastcall _op_LessThanOrEqual(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Addition(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Subtraction(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Multiply(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Division(const TFoo A, const TFoo B);
static TFoo __fastcall _op_IntDivide(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Modulus(const TFoo A, const TFoo B);
static TFoo __fastcall _op_LeftShift(const TFoo A, const TFoo B);
static TFoo __fastcall _op_RightShift(const TFoo A, const TFoo B);
static TFoo __fastcall _op_LogicalAnd(const TFoo A, const TFoo B);
static TFoo __fastcall _op_LogicalOr(const TFoo A, const TFoo B);
static TFoo __fastcall _op_ExclusiveOr(const TFoo A, const TFoo B);
static TFoo __fastcall _op_BitwiseAnd(const TFoo A, const TFoo B);
static TFoo __fastcall _op_BitwiseOr(const TFoo A, const TFoo B);
static TFoo __fastcall _op_BitwiseXOR(const TFoo A, const TFoo B);
static void __fastcall _op_Assign(TFoo &Dest, TFoo &Src);
static TFoo __fastcall _op_Include(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Exclude(const TFoo A, const TFoo B);
static bool __fastcall _op_True(const TFoo Src);
static bool __fastcall _op_False(const TFoo Src);
static TFoo __fastcall _op_OnesComplement(const TFoo Src);
__property int Value = {read=FValue};
TFoo() {}

TFoo& operator =(int AValue) { *this = TFoo::_op_Implicit(AValue); return *this; }
TFoo operator -() { return TFoo::_op_UnaryNegation(*this); }
TFoo operator +() { return TFoo::_op_UnaryPlus(*this); }
TFoo operator !() { return TFoo::_op_LogicalNot(*this); }
TFoo& operator ++() { *this = TFoo::_op_Increment(*this); return *this; }
TFoo operator ++(int) { TFoo tmp = *this; *this = TFoo::_op_Increment(*this); return tmp; }
TFoo& operator --() { *this = TFoo::_op_Decrement(*this); return *this; }
TFoo operator --(int) { TFoo tmp = *this; *this = TFoo::_op_Decrement(*this); return tmp; }
friend bool operator ==(const TFoo A, const TFoo B) { return TFoo::_op_Equality(A, B); }
friend bool operator !=(const TFoo A, const TFoo B) { return TFoo::_op_Inequality(A, B); }
friend bool operator >(const TFoo A, const TFoo B) { return TFoo::_op_GreaterThan(A, B); }
friend bool operator >=(const TFoo A, const TFoo B) { return TFoo::_op_GreaterThanOrEqual(A, B); }
friend bool operator <(const TFoo A, const TFoo B) { return TFoo::_op_LessThan(A, B); }
friend bool operator <=(const TFoo A, const TFoo B) { return TFoo::_op_LessThanOrEqual(A, B); }
friend TFoo operator +(const TFoo A, const TFoo B) { return TFoo::_op_Addition(A, B); }
friend TFoo operator -(const TFoo A, const TFoo B) { return TFoo::_op_Subtraction(A, B); }
friend TFoo operator *(const TFoo A, const TFoo B) { return TFoo::_op_Multiply(A, B); }
friend TFoo operator /(const TFoo A, const TFoo B) { return TFoo::_op_Division(A, B); }
friend TFoo operator %(const TFoo A, const TFoo B) { return TFoo::_op_Modulus(A, B); }
friend TFoo operator <<(const TFoo A, const TFoo B) { return TFoo::_op_LeftShift(A, B); }
friend TFoo operator >>(const TFoo A, const TFoo B) { return TFoo::_op_RightShift(A, B); }
friend TFoo operator &&(const TFoo A, const TFoo B) { return TFoo::_op_LogicalAnd(A, B); }
friend TFoo operator ||(const TFoo A, const TFoo B) { return TFoo::_op_LogicalOr(A, B); }
friend TFoo operator &(const TFoo A, const TFoo B) { return TFoo::_op_BitwiseAnd(A, B); }
friend TFoo operator |(const TFoo A, const TFoo B) { return TFoo::_op_BitwiseOr(A, B); }
friend TFoo operator ^(const TFoo A, const TFoo B) { return TFoo::_op_BitwiseXOR(A, B); }
TFoo operator ~() { return TFoo::_op_OnesComplement(*this); }
};
```

#### Name data

| Public operator name | Internal class function name |
|----------------------|------------------------------|
| `Implicit` | `&&op_Implicit` |
| `Explicit` | `&&op_Explicit` |
| `Negative` | `&&op_UnaryNegation` |
| `Positive` | `&&op_UnaryPlus` |
| `LogicalNot` | `&&op_LogicalNot` |
| `Inc` | `&&op_Increment` |
| `Dec` | `&&op_Decrement` |
| `Trunc` | `&&op_Trunc` |
| `Round` | `&&op_Round` |
| `In` | `&&op_In` |
| `Equal` | `&&op_Equality` |
| `NotEqual` | `&&op_Inequality` |
| `GreaterThan` | `&&op_GreaterThan` |
| `GreaterThanOrEqual` | `&&op_GreaterThanOrEqual` |
| `LessThan` | `&&op_LessThan` |
| `LessThanOrEqual` | `&&op_LessThanOrEqual` |
| `Add` | `&&op_Addition` |
| `Subtract` | `&&op_Subtraction` |
| `Multiply` | `&&op_Multiply` |
| `Divide` | `&&op_Division` |
| `IntDivide` | `&&op_IntDivide` |
| `Modulus` | `&&op_Modulus` |
| `LeftShift` | `&&op_LeftShift` |
| `RightShift` | `&&op_RightShift` |
| `LogicalAnd` | `&&op_LogicalAnd` |
| `LogicalOr` | `&&op_LogicalOr` |
| `LogicalXor` | `&&op_ExclusiveOr` |
| `BitwiseAnd` | `&&op_BitwiseAnd` |
| `BitwiseOr` | `&&op_BitwiseOr` |
| `BitwiseXor` | `&&op_BitwiseXOR` |
| `Assign` | `&&op_Assign` |
| `Include` | `&&op_Include` |
| `Exclude` | `&&op_Exclude` |
| `True` | `&&op_True` |
| `False` | `&&op_False` |
| `OnesComplement` | `&&op_OnesComplement` |

### Rationale

Some Delphi libraries actually make use of this undocumented language "feature" to provide operator overloads in record helpers.

Spring4D is the most prominent example, using this approach to polyfill older versions of Delphi:
```pas
{$IFNDEF DELPHIXE3_UP}
TMethodHelper = record helper for TMethod
public
class function &&op_Equality(const left, right: TMethod): Boolean; static; inline;
class function &&op_Inequality(const left, right: TMethod): Boolean; static; inline;
class function &&op_GreaterThan(const left, right: TMethod): Boolean; static; inline;
class function &&op_LessThan(const left, right: TMethod): Boolean; static; inline;
end;
{$ENDIF}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.