فهرست منبع

fcl-passrc: pasuseanalyzer: no hint assigned but never used for out argument

git-svn-id: trunk@35720 -
Mattias Gaertner 8 سال پیش
والد
کامیت
e71ac95b69

+ 3 - 25
packages/fcl-passrc/src/pasresolver.pp

@@ -5209,6 +5209,7 @@ begin
   if (Ref.Access=Access) then exit;
   if Access in [rraNone,rraParamToUnknownProc] then
     exit;
+  if Expr=nil then ;
 
   case Ref.Access of
     rraNone,rraParamToUnknownProc:
@@ -5228,31 +5229,6 @@ begin
   else
     RaiseInternalError(20170403163727);
   end;
-
-  if (Expr.ClassType=TSelfExpr)
-      or ((Expr.ClassType=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then
-    begin
-    if Ref.WithExprScope<>nil then
-      begin
-      if Ref.WithExprScope.Scope is TPasRecordScope then
-        begin
-        // a record member was accessed -> access the record too
-        AccessExpr(Ref.WithExprScope.Expr,Access);
-        exit;
-        end;
-      end;
-    if (Ref.Declaration is TPasVariable)
-        and (Expr.Parent is TBinaryExpr)
-        and (TBinaryExpr(Expr.Parent).right=Expr) then
-      begin
-      if ((Ref.Declaration.Parent is TPasRecordType)
-            or (Ref.Declaration.Parent is TPasVariant)) then
-        begin
-        // a record member was accessed -> access the record too
-        AccessExpr(TBinaryExpr(Expr.Parent).left,Access);
-        end;
-      end;
-    end;
 end;
 
 procedure TPasResolver.AccessExpr(Expr: TPasExpr;
@@ -5297,6 +5273,8 @@ begin
     pekSet:
       if Access<>rraRead then
         RaiseMsg(20170306112306,nVariableIdentifierExpected,sVariableIdentifierExpected,[],Expr);
+    else
+      RaiseNotYetImplemented(20170403173831,Params);
     end;
     end
   else if (C=TSelfExpr) or ((C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then

+ 89 - 2
packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -193,6 +193,8 @@ type
     procedure UseImplBlock(Block: TPasImplBlock; Mark: boolean); virtual;
     procedure UseImplElement(El: TPasImplElement); virtual;
     procedure UseExpr(El: TPasExpr); virtual;
+    procedure UseExprRef(Expr: TPasExpr; Access: TResolvedRefAccess;
+      UseFull: boolean); virtual;
     procedure UseProcedure(Proc: TPasProcedure); virtual;
     procedure UseProcedureType(ProcType: TPasProcedureType; Mark: boolean); virtual;
     procedure UseType(El: TPasType; Mode: TPAUseMode); virtual;
@@ -877,13 +879,39 @@ var
   i: Integer;
 begin
   if El=nil then exit;
-  // expression are not marked
+  // expressions are not marked
 
   if El.CustomData is TResolvedReference then
     begin
     // this is a reference -> mark target
     Ref:=TResolvedReference(El.CustomData);
     UseElement(Ref.Declaration,Ref.Access,false);
+
+    if (El.ClassType=TSelfExpr)
+        or ((El.ClassType=TPrimitiveExpr) and (TPrimitiveExpr(El).Kind=pekIdent)) then
+      begin
+      if Ref.WithExprScope<>nil then
+        begin
+        if Ref.WithExprScope.Scope is TPasRecordScope then
+          begin
+          // a record member was accessed -> access the record too
+          UseExprRef(Ref.WithExprScope.Expr,Ref.Access,false);
+          exit;
+          end;
+        end;
+      if (Ref.Declaration is TPasVariable)
+          and (El.Parent is TBinaryExpr)
+          and (TBinaryExpr(El.Parent).right=El) then
+        begin
+        if ((Ref.Declaration.Parent is TPasRecordType)
+              or (Ref.Declaration.Parent is TPasVariant)) then
+          begin
+          // a record member was accessed -> access the record too
+          UseExprRef(TBinaryExpr(El.Parent).left,Ref.Access,false);
+          end;
+        end;
+      end;
+
     end;
   UseExpr(El.format1);
   UseExpr(El.format2);
@@ -911,6 +939,65 @@ begin
     RaiseNotSupported(20170307085444,El);
 end;
 
+procedure TPasAnalyzer.UseExprRef(Expr: TPasExpr; Access: TResolvedRefAccess;
+  UseFull: boolean);
+var
+  Ref: TResolvedReference;
+  C: TClass;
+  Bin: TBinaryExpr;
+  Params: TParamsExpr;
+  ValueResolved: TPasResolverResult;
+begin
+  if (Expr.CustomData is TResolvedReference) then
+    begin
+    Ref:=TResolvedReference(Expr.CustomData);
+    UseElement(Ref.Declaration,Access,UseFull);
+    end;
+
+  C:=Expr.ClassType;
+  if C=TBinaryExpr then
+    begin
+    Bin:=TBinaryExpr(Expr);
+    if Bin.OpCode in [eopSubIdent,eopNone] then
+      UseExprRef(Bin.right,Access,UseFull);
+    end
+  else if C=TParamsExpr then
+    begin
+    Params:=TParamsExpr(Expr);
+    case Params.Kind of
+    pekFuncParams:
+      if Resolver.IsTypeCast(Params) then
+        UseExprRef(Params.Params[0],Access,UseFull)
+      else
+        UseExprRef(Params.Value,Access,UseFull);
+    pekArrayParams:
+      begin
+      Resolver.ComputeElement(Params.Value,ValueResolved,[]);
+      if not Resolver.IsDynArray(ValueResolved.TypeEl) then
+        UseExprRef(Params.Value,Access,UseFull);
+      end;
+    pekSet: ;
+    else
+      RaiseNotSupported(20170403173817,Params);
+    end;
+    end
+  else if (C=TSelfExpr) or ((C=TPrimitiveExpr) and (TPrimitiveExpr(Expr).Kind=pekIdent)) then
+    // ok
+  else if (Access=rraRead)
+      and ((C=TPrimitiveExpr)
+        or (C=TNilExpr)
+        or (C=TBoolConstExpr)
+        or (C=TUnaryExpr)) then
+    // ok
+  else
+    begin
+    {$IFDEF VerbosePasResolver}
+    writeln('TPasResolver.UseExprRef Expr=',GetObjName(Expr),' Access=',Access,' Declaration="',Expr.GetDeclaration(false),'"');
+    {$ENDIF}
+    RaiseNotSupported(20170306102158,Expr);
+    end;
+end;
+
 procedure TPasAnalyzer.UseProcedure(Proc: TPasProcedure);
 
   procedure UseOverrides(CurProc: TPasProcedure);
@@ -1531,7 +1618,7 @@ begin
       else
         begin
         // parameter was used
-        if Usage.Access=paiaWrite then
+        if (Usage.Access=paiaWrite) and (Arg.Access<>argOut) then
           EmitMessage(20170312095348,mtHint,nPAValueParameterIsAssignedButNeverUsed,
             sPAValueParameterIsAssignedButNeverUsed,[Arg.Name],Arg);
         end;

+ 2 - 2
packages/fcl-passrc/tests/tcresolver.pas

@@ -4046,8 +4046,8 @@ begin
   Add('begin');
   Add('  DoIt({#r1_read}r.{#r_a1_read}a,');
   Add('    {#r2_read}r.{#r_a2_read}a,');
-  Add('    {#r3_readandassign}r.{#r_a3_var}a,');
-  Add('    {#r4_readandassign}r.{#r_a4_out}a);');
+  Add('    {#r3_read}r.{#r_a3_var}a,');
+  Add('    {#r4_read}r.{#r_a4_out}a);');
   Add('  with r do');
   Add('    DoIt({#w_a1_read}a,');
   Add('      {#w_a2_read}a,');

+ 27 - 5
packages/fcl-passrc/tests/tcuseanalyzer.pas

@@ -92,6 +92,7 @@ type
     procedure TestM_Hint_FunctionResultDoesNotSeemToBeSet;
     procedure TestM_Hint_FunctionResultRecord;
     procedure TestM_Hint_FunctionResultPassRecordElement;
+    procedure TestM_Hint_OutParam_No_AssignedButNeverUsed;
 
     // whole program optimization
     procedure TestWP_LocalVar;
@@ -233,13 +234,19 @@ begin
   while i>=0 do
     begin
     Msg:=PAMessages[i];
-    if (Msg.MsgType=MsgType)
-        and (Msg.MsgNumber=MsgNumber)
-        and (Msg.MsgText=MsgText) then
+    if (Msg.MsgNumber=MsgNumber) then
       begin
       if Has then
-        exit;
-      break;
+        begin
+        // must have -> message type and text must match exactly
+        if (Msg.MsgType=MsgType) and (Msg.MsgText=MsgText) then
+          exit;
+        end
+      else
+        begin
+        // must not have -> matching number is enough
+        break;
+        end;
       end;
     dec(i);
     end;
@@ -1168,6 +1175,21 @@ begin
     sPAFunctionResultDoesNotSeemToBeSet,false);
 end;
 
+procedure TTestUseAnalyzer.TestM_Hint_OutParam_No_AssignedButNeverUsed;
+begin
+  StartProgram(true);
+  Add('procedure DoIt(out x: longint);');
+  Add('begin');
+  Add('  x:=3;');
+  Add('end;');
+  Add('var i: longint;');
+  Add('begin');
+  Add('  DoIt(i);');
+  AnalyzeProgram;
+  CheckHasHint(mtHint,nPAValueParameterIsAssignedButNeverUsed,
+    sPAValueParameterIsAssignedButNeverUsed,false);
+end;
+
 procedure TTestUseAnalyzer.TestWP_LocalVar;
 begin
   StartProgram(false);