fcl-passrc: parse and resolve method modifier message

git-svn-id: trunk@41582 -
This commit is contained in:
Mattias Gaertner 2019-03-03 21:44:42 +00:00
parent 72196141b0
commit cbdd7e892f
5 changed files with 78 additions and 14 deletions

View File

@ -181,7 +181,7 @@ const
nDerivedXMustExtendASubClassY = 3115; nDerivedXMustExtendASubClassY = 3115;
nDefaultPropertyNotAllowedInHelperForX = 3116; nDefaultPropertyNotAllowedInHelperForX = 3116;
nHelpersCannotBeUsedAsTypes = 3117; nHelpersCannotBeUsedAsTypes = 3117;
// free 3118 nMessageHandlersInvalidParams = 3118;
nImplictConversionUnicodeToAnsi = 3119; nImplictConversionUnicodeToAnsi = 3119;
nWrongTypeXInArrayConstructor = 3120; nWrongTypeXInArrayConstructor = 3120;
nUnknownCustomAttributeX = 3121; nUnknownCustomAttributeX = 3121;
@ -315,7 +315,7 @@ resourcestring
sDerivedXMustExtendASubClassY = 'Derived %s must extend a subclass of "%s" or the class itself'; sDerivedXMustExtendASubClassY = 'Derived %s must extend a subclass of "%s" or the class itself';
sDefaultPropertyNotAllowedInHelperForX = 'Default property not allowed in helper for %s'; sDefaultPropertyNotAllowedInHelperForX = 'Default property not allowed in helper for %s';
sHelpersCannotBeUsedAsTypes = 'helpers cannot be used as types'; sHelpersCannotBeUsedAsTypes = 'helpers cannot be used as types';
// was 3118 sMessageHandlersInvalidParams = 'Message handlers can take only one call by ref. parameter';
sImplictConversionUnicodeToAnsi = 'Implicit string type conversion with potential data loss from "UnicodeString" to "AnsiString"'; sImplictConversionUnicodeToAnsi = 'Implicit string type conversion with potential data loss from "UnicodeString" to "AnsiString"';
sWrongTypeXInArrayConstructor = 'Wrong type "%s" in array constructor'; sWrongTypeXInArrayConstructor = 'Wrong type "%s" in array constructor';
sUnknownCustomAttributeX = 'Unknown custom attribute "%s"'; sUnknownCustomAttributeX = 'Unknown custom attribute "%s"';

View File

@ -5847,6 +5847,8 @@ var
ObjKind: TPasObjKind; ObjKind: TPasObjKind;
ParentBody: TProcedureBody; ParentBody: TProcedureBody;
HelperForType: TPasType; HelperForType: TPasType;
Args: TFPList;
Arg: TPasArgument;
begin begin
if El.Parent is TPasProcedure then if El.Parent is TPasProcedure then
Proc:=TPasProcedure(El.Parent) Proc:=TPasProcedure(El.Parent)
@ -6046,10 +6048,28 @@ begin
if El is TPasFunctionType then if El is TPasFunctionType then
EmitTypeHints(TPasFunctionType(El).ResultEl,TPasFunctionType(El).ResultEl.ResultType); EmitTypeHints(TPasFunctionType(El).ResultEl,TPasFunctionType(El).ResultEl.ResultType);
if Proc.PublicName<>nil then
ResolveExpr(Proc.PublicName,rraRead);
if Proc.LibraryExpr<>nil then if Proc.LibraryExpr<>nil then
ResolveExpr(Proc.LibraryExpr,rraRead); ResolveExpr(Proc.LibraryExpr,rraRead);
if Proc.LibrarySymbolName<>nil then if Proc.LibrarySymbolName<>nil then
ResolveExpr(Proc.LibrarySymbolName,rraRead); ResolveExpr(Proc.LibrarySymbolName,rraRead);
if Proc.DispIDExpr<>nil then
ResolveExpr(Proc.DispIDExpr,rraRead);
if Proc.MessageExpr<>nil then
begin
// message modifier
ResolveExpr(Proc.MessageExpr,rraRead);
Args:=Proc.ProcType.Args;
if Args.Count<>1 then
RaiseMsg(20190303223701,nMessageHandlersInvalidParams,sMessageHandlersInvalidParams,[],El);
Arg:=TPasArgument(Args[0]);
if not (Arg.Access in [argVar,argOut]) then
RaiseMsg(20190303223834,nMessageHandlersInvalidParams,sMessageHandlersInvalidParams,[],El);
if (Proc.ClassType<>TPasProcedure)
and (Proc.ClassType<>TPasFunction) then
RaiseMsg(20190303224128,nXExpectedButYFound,sXExpectedButYFound,['procedure name(var Msg);message id;',GetElementTypeName(El)],El);
end;
if Proc.Parent is TPasMembersType then if Proc.Parent is TPasMembersType then
begin begin

View File

@ -1054,6 +1054,7 @@ type
LibrarySymbolName, LibrarySymbolName,
LibraryExpr : TPasExpr; // e.g. external LibraryExpr name LibrarySymbolName; LibraryExpr : TPasExpr; // e.g. external LibraryExpr name LibrarySymbolName;
DispIDExpr : TPasExpr; DispIDExpr : TPasExpr;
MessageExpr: TPasExpr;
AliasName : String; AliasName : String;
ProcType : TPasProcedureType; ProcType : TPasProcedureType;
Body : TProcedureBody; Body : TProcedureBody;
@ -3398,6 +3399,7 @@ begin
ReleaseAndNil(TPasElement(LibraryExpr){$IFDEF CheckPasTreeRefCount},'TPasProcedure.LibraryExpr'{$ENDIF}); ReleaseAndNil(TPasElement(LibraryExpr){$IFDEF CheckPasTreeRefCount},'TPasProcedure.LibraryExpr'{$ENDIF});
ReleaseAndNil(TPasElement(LibrarySymbolName){$IFDEF CheckPasTreeRefCount},'TPasProcedure.LibrarySymbolName'{$ENDIF}); ReleaseAndNil(TPasElement(LibrarySymbolName){$IFDEF CheckPasTreeRefCount},'TPasProcedure.LibrarySymbolName'{$ENDIF});
ReleaseAndNil(TPasElement(DispIDExpr){$IFDEF CheckPasTreeRefCount},'TPasProcedure.DispIDExpr'{$ENDIF}); ReleaseAndNil(TPasElement(DispIDExpr){$IFDEF CheckPasTreeRefCount},'TPasProcedure.DispIDExpr'{$ENDIF});
ReleaseAndNil(TPasElement(MessageExpr){$IFDEF CheckPasTreeRefCount},'TPasProcedure.MessageExpr'{$ENDIF});
ReleaseAndNil(TPasElement(ProcType){$IFDEF CheckPasTreeRefCount},'TPasProcedure.ProcType'{$ENDIF}); ReleaseAndNil(TPasElement(ProcType){$IFDEF CheckPasTreeRefCount},'TPasProcedure.ProcType'{$ENDIF});
ReleaseAndNil(TPasElement(Body){$IFDEF CheckPasTreeRefCount},'TPasProcedure.Body'{$ENDIF}); ReleaseAndNil(TPasElement(Body){$IFDEF CheckPasTreeRefCount},'TPasProcedure.Body'{$ENDIF});
inherited Destroy; inherited Destroy;
@ -4472,6 +4474,7 @@ begin
ForEachChildCall(aMethodCall,Arg,PublicName,false); ForEachChildCall(aMethodCall,Arg,PublicName,false);
ForEachChildCall(aMethodCall,Arg,LibraryExpr,false); ForEachChildCall(aMethodCall,Arg,LibraryExpr,false);
ForEachChildCall(aMethodCall,Arg,LibrarySymbolName,false); ForEachChildCall(aMethodCall,Arg,LibrarySymbolName,false);
ForEachChildCall(aMethodCall,Arg,MessageExpr,false);
ForEachChildCall(aMethodCall,Arg,Body,false); ForEachChildCall(aMethodCall,Arg,Body,false);
end; end;

View File

@ -4866,21 +4866,24 @@ begin
end; end;
pmMessage: pmMessage:
begin begin
Repeat NextToken;
NextToken; E:=DoParseExpression(Parent);
If CurToken<>tkSemicolon then TPasProcedure(Parent).MessageExpr:=E;
begin if E is TPrimitiveExpr then
if Parent is TPasProcedure then begin
TPasProcedure(Parent).MessageName:=CurtokenString; TPasProcedure(Parent).MessageName:=TPrimitiveExpr(E).Value;
If (CurToken=tkString) and (Parent is TPasProcedure) then case E.Kind of
TPasProcedure(Parent).Messagetype:=pmtString; pekNumber, pekUnary: TPasProcedure(Parent).Messagetype:=pmtInteger;
end; pekString: TPasProcedure(Parent).Messagetype:=pmtString;
until CurToken = tkSemicolon; end;
UngetToken; end;
if CurToken = tkSemicolon then
UngetToken;
end; end;
pmDispID: pmDispID:
begin begin
TPasProcedure(Parent).DispIDExpr:=DoParseExpression(Parent,Nil); NextToken;
TPasProcedure(Parent).DispIDExpr:=DoParseExpression(Parent);
if CurToken = tkSemicolon then if CurToken = tkSemicolon then
UngetToken; UngetToken;
end; end;

View File

@ -620,6 +620,8 @@ type
Procedure TestClass_EnumeratorFunc; Procedure TestClass_EnumeratorFunc;
Procedure TestClass_ForInPropertyStaticArray; Procedure TestClass_ForInPropertyStaticArray;
Procedure TestClass_TypeAlias; Procedure TestClass_TypeAlias;
Procedure TestClass_Message;
Procedure TestClass_Message_MissingParamFail;
// published // published
Procedure TestClass_PublishedClassVarFail; Procedure TestClass_PublishedClassVarFail;
@ -11118,6 +11120,42 @@ begin
ParseProgram; ParseProgram;
end; end;
procedure TTestResolver.TestClass_Message;
begin
StartProgram(false);
Add([
'const',
' FlyId = 2;',
' RunStr = ''Fast'';',
'type',
' TObject = class',
' procedure Fly(var msg); message 3+FlyId;',
' procedure Run(var msg); virtual; abstract; message ''prefix''+RunStr;',
' end;',
'procedure TObject.Fly(var msg);',
'begin',
'end;',
'begin',
'']);
ParseProgram;
end;
procedure TTestResolver.TestClass_Message_MissingParamFail;
begin
StartProgram(false);
Add([
'type',
' TObject = class',
' procedure Fly; message 3;',
' end;',
'procedure TObject.Fly;',
'begin',
'end;',
'begin',
'']);
CheckResolverException(sMessageHandlersInvalidParams,nMessageHandlersInvalidParams);
end;
procedure TTestResolver.TestClass_PublishedClassVarFail; procedure TTestResolver.TestClass_PublishedClassVarFail;
begin begin
StartProgram(false); StartProgram(false);