diff --git a/packages/fcl-passrc/src/pasuseanalyzer.pas b/packages/fcl-passrc/src/pasuseanalyzer.pas index f09b680c73..7a459335c1 100644 --- a/packages/fcl-passrc/src/pasuseanalyzer.pas +++ b/packages/fcl-passrc/src/pasuseanalyzer.pas @@ -283,6 +283,7 @@ type procedure EmitTypeHints(El: TPasType); virtual; procedure EmitVariableHints(El: TPasVariable); virtual; procedure EmitProcedureHints(El: TPasProcedure); virtual; + procedure EmitFunctionResultHints(El: TPasFunction); virtual; public constructor Create; destructor Destroy; override; @@ -2620,9 +2621,7 @@ var Arg: TPasArgument; Usage: TPAElement; ProcScope: TPasProcedureScope; - PosEl: TPasElement; DeclProc, ImplProc: TPasProcedure; - FuncType: TPasFunctionType; begin {$IFDEF VerbosePasAnalyzer} writeln('TPasAnalyzer.EmitProcedureHints ',GetElModName(El)); @@ -2689,22 +2688,7 @@ begin end; // check result if (El.ProcType is TPasFunctionType) then - begin - FuncType:=TPasFunctionType(TPasProcedure(El).ProcType); - PosEl:=FuncType.ResultEl; - if (ProcScope.ImplProc<>nil) - and (TPasFunction(ProcScope.ImplProc).FuncType.ResultEl<>nil) then - PosEl:=TPasFunction(ProcScope.ImplProc).FuncType.ResultEl; - Usage:=FindElement(FuncType.ResultEl); - if (Usage=nil) or (Usage.Access in [paiaNone,paiaRead]) then - // result was never used - EmitMessage(20170313214038,mtHint,nPAFunctionResultDoesNotSeemToBeSet, - sPAFunctionResultDoesNotSeemToBeSet,[],PosEl) - else - begin - // result was used - end; - end; + EmitFunctionResultHints(TPasFunction(El)); end; if El.Body<>nil then @@ -2715,6 +2699,55 @@ begin end; end; +procedure TPasAnalyzer.EmitFunctionResultHints(El: TPasFunction); +var + FuncType: TPasFunctionType; + Usage: TPAElement; + TypeEl: TPasType; + Members: TFPList; + i: Integer; + Member: TPasElement; + HasFields: Boolean; + PosEl: TPasResultElement; + ProcScope: TPasProcedureScope; +begin + FuncType:=El.FuncType; + Usage:=FindElement(FuncType.ResultEl); + if (Usage=nil) or (Usage.Access in [paiaNone,paiaRead]) then + begin + // result was never set + TypeEl:=Resolver.ResolveAliasType(FuncType.ResultEl.ResultType); + if TypeEl is TPasRecordType then + begin + Members:=TPasRecordType(TypeEl).Members; + HasFields:=false; + for i:=0 to Members.Count-1 do + begin + Member:=TPasElement(Members[i]); + if Member.ClassType=TPasVariable then + begin + HasFields:=true; + break; + end; + end; + if not HasFields then + // empty record -> no hint + exit; + end; + PosEl:=FuncType.ResultEl; + ProcScope:=El.CustomData as TPasProcedureScope; + if (ProcScope.ImplProc<>nil) + and (TPasFunction(ProcScope.ImplProc).FuncType.ResultEl<>nil) then + PosEl:=TPasFunction(ProcScope.ImplProc).FuncType.ResultEl; + EmitMessage(20170313214038,mtHint,nPAFunctionResultDoesNotSeemToBeSet, + sPAFunctionResultDoesNotSeemToBeSet,[],PosEl) + end + else + begin + // result was used + end; +end; + constructor TPasAnalyzer.Create; var m: TPAUseMode; diff --git a/packages/fcl-passrc/tests/tcuseanalyzer.pas b/packages/fcl-passrc/tests/tcuseanalyzer.pas index 4874fe83a6..983fa4a653 100644 --- a/packages/fcl-passrc/tests/tcuseanalyzer.pas +++ b/packages/fcl-passrc/tests/tcuseanalyzer.pas @@ -129,6 +129,7 @@ type procedure TestM_Hint_FunctionResultDoesNotSeemToBeSet; procedure TestM_Hint_FunctionResultDoesNotSeemToBeSet_Abstract; procedure TestM_Hint_FunctionResultRecord; + procedure TestM_Hint_FunctionResultRecordEmpty; procedure TestM_Hint_FunctionResultPassRecordElement; procedure TestM_Hint_FunctionResultAssembler; procedure TestM_Hint_FunctionResultExit; @@ -2198,6 +2199,25 @@ begin CheckUseAnalyzerUnexpectedHints; end; +procedure TTestUseAnalyzer.TestM_Hint_FunctionResultRecordEmpty; +begin + StartProgram(true); + Add([ + '{$modeswitch AdvancedRecords}', + 'type', + ' TEmpty = record', + ' class function Create: TEmpty; static;', + ' end;', + 'class function TEmpty.Create: TEmpty;', + 'begin', + 'end;', + 'begin', + ' TEmpty.Create;', + '']); + AnalyzeProgram; + CheckUseAnalyzerUnexpectedHints; +end; + procedure TTestUseAnalyzer.TestM_Hint_FunctionResultPassRecordElement; begin StartProgram(true);