CodeTool: Improve tracking specialized generic parameters (e.g. variable class base).

Undo/Replace commits:
- 797768a965, Branch RevNo: 58874
  codetools: code completion for "FOR var IN" with generic class, from Pascal Riekenberg
  git-svn-id: trunk@63136 -
- 4d12a06af5, Branch RevNo: 62044
  CodeTools: Resolve generic params when searching in ancestors.
This commit is contained in:
Martin 2022-10-19 02:21:06 +02:00
parent a44d1ab453
commit d488d45819
3 changed files with 1405 additions and 537 deletions

View File

@ -551,30 +551,12 @@ type
property Tree: TAVLTree read FTree;
end;
{ TGenericParamValueMapping }
TGenericParamValueMapping = packed class
NextBrother: TGenericParamValueMapping;
GenericParamNode,
SpecializeValueNode: TCodeTreeNode;
constructor Create(pPrevBrother: TGenericParamValueMapping; pParam, pValue: TCodeTreeNode);
destructor Destroy; override;
end;
{ TGenericParamValueMappings }
TGenericParamValueMappings = record
SpecializeParamsTool: TFindDeclarationTool;
SpecializeParamsNode: TCodeTreeNode;
SpecializeValuesTool: TFindDeclarationTool;
FirstParamValueMapping: TGenericParamValueMapping;
end;
{ TGenericParams }
TGenericParams = record
ParamValuesTool: TFindDeclarationTool;
SpecializeParamsNode: TCodeTreeNode;
OuterGenParam: array of TGenericParams;
end;
TFindDeclarationInput = record
@ -615,7 +597,6 @@ type
FHelpers: array[TFDHelpersListKind] of TFDHelpersList;
FFreeHelpers: array[TFDHelpersListKind] of Boolean;
FNeedHelpers: Boolean;
GenParamValueMappings: TGenericParamValueMappings;
procedure ClearFoundProc;
procedure FreeFoundProc(aFoundProc: PFoundProc; FreeNext: boolean);
procedure RemoveFoundProcFromList(aFoundProc: PFoundProc);
@ -627,9 +608,6 @@ type
private
procedure SetGenericParamValues(SpecializeParamsTool: TFindDeclarationTool;
SpecializeNode: TCodeTreeNode);
procedure UpdateGenericParamMapping(SpecializeParamsTool: TFindDeclarationTool;
SpecializeParamsNode: TCodeTreeNode; GenericParamsNode: TCodeTreeNode);
function UpdateContexWithGenParamValue(var SpecializeParamContext: TFindContext): Boolean;
function FindGenericParamType: Boolean;
procedure AddOperandPart(aPart: string);
property ExtractedOperand: string read FExtractedOperand;
@ -875,9 +853,6 @@ type
TermCleanPos: integer;
AliasType: PFindContext = nil): string;
protected
// find the declared type "TMyObject" of a generic-param "generic TFoo<_P1: TMyObject>"
function FindClassFromGenericParamType(GenParamNode: TCodeTreeNode;
ResultParams: TFindDeclarationParams): boolean;
function CheckSrcIdentifier(Params: TFindDeclarationParams;
const FoundContext: TFindContext): TIdentifierFoundResult;
function FindDeclarationOfIdentAtParam(
@ -1577,23 +1552,6 @@ begin
ListOfPFindContext:=nil;
end;
{ TGenericParamValueMapping }
constructor TGenericParamValueMapping.Create(pPrevBrother: TGenericParamValueMapping; pParam, pValue: TCodeTreeNode);
begin
if pPrevBrother <> nil then
pPrevBrother.NextBrother := Self;
GenericParamNode := pParam;
SpecializeValueNode := pValue;
end;
destructor TGenericParamValueMapping.Destroy;
begin
if NextBrother <> nil then
NextBrother.Free;
inherited Destroy;
end;
{ TFindIdentifierInUsesSection_FindMissingFPCUnit }
constructor TFindIdentifierInUsesSection_FindMissingFPCUnit.Create;
@ -4191,111 +4149,118 @@ var
// returns: true to stop search
// false if search should continue
begin
Result:=true;
FindIdentifierInContext:=NewResult and (not (fdfCollect in Flags));
{$IFDEF ShowCollect}
if fdfCollect in Flags then begin
DebugLn('[TFindDeclarationTool.FindIdentifierInContext.CheckResult] COLLECT CheckResult Ident=',
'"',GetIdentifier(Params.Identifier),'"',
' File="',ExtractFilename(MainFilename)+'"',
' Flags=[',dbgs(Flags)+']',
' NewResult=',DbgS(NewResult),
' CallOnIdentifierFound=',DbgS(CallOnIdentifierFound));
end;
{$ENDIF}
if NewResult then begin
// identifier found
{$IFDEF ShowFoundIdentifier}
debugln(['CheckResult FOUND ',GetIdentifier(Params.Identifier)]);
Params.WriteDebugReport;
{$ENDIF}
if fdfExtractOperand in Flags then
case Params.NewNode.Desc of
ctnVarDefinition, ctnConstDefinition:
with Params do
AddOperandPart(GetIdentifier(@NewCodeTool.Src[NewNode.StartPos]));
ctnProperty,ctnGlobalProperty:
begin
if fdfPropertyResolving in Flags then begin
if not PropNodeIsTypeLess(Params.NewNode)
and ReadTilGetterOfProperty(Params.NewNode) then begin
// continue searching of getter
Params.Identifier := @Src[CurPos.StartPos];
end;
ContextNode := Params.NewNode;
Exit(False);
end else
Params.AddOperandPart(GetIdentifier(Params.Identifier));
end;
ctnProcedure:
begin
Params.AddOperandPart(ExtractProcName(Params.NewNode,[]));
// ToDo: add default parameters
end;
end;
if CallOnIdentifierFound then begin
{debugln(['[TFindDeclarationTool.FindIdentifierInContext.CheckResult] CallOnIdentifierFound Ident=',
try
Result:=true;
FindIdentifierInContext:=NewResult and (not (fdfCollect in Flags));
{$IFDEF ShowCollect}
if fdfCollect in Flags then begin
DebugLn('[TFindDeclarationTool.FindIdentifierInContext.CheckResult] COLLECT CheckResult Ident=',
'"',GetIdentifier(Params.Identifier),'"',
' StartContext="',StartContextNode.DescAsString,'" "',copy(Src,StartContextNode.StartPos,20),'"',
' File="',ExtractFilename(MainFilename)+'"',
' Flags=[',dbgs(Flags),']'
]);}
IdentFoundResult:=Params.NewCodeTool.DoOnIdentifierFound(Params,
Params.NewNode);
{$IFDEF ShowProcSearch}
DebugLn(['[TFindDeclarationTool.FindIdentifierInContext.CheckResult] DoOnIdentifierFound=',IdentifierFoundResultNames[IdentFoundResult]]);
' Flags=[',dbgs(Flags)+']',
' NewResult=',DbgS(NewResult),
' CallOnIdentifierFound=',DbgS(CallOnIdentifierFound));
end;
{$ENDIF}
if NewResult then begin
// identifier found
{$IFDEF ShowFoundIdentifier}
debugln(['CheckResult FOUND ',GetIdentifier(Params.Identifier)]);
Params.WriteDebugReport;
{$ENDIF}
if (IdentFoundResult=ifrSuccess) then
if fdfExtractOperand in Flags then
case Params.NewNode.Desc of
ctnVarDefinition, ctnConstDefinition:
with Params do
AddOperandPart(GetIdentifier(@NewCodeTool.Src[NewNode.StartPos]));
ctnProperty,ctnGlobalProperty:
begin
if fdfPropertyResolving in Flags then begin
if not PropNodeIsTypeLess(Params.NewNode)
and ReadTilGetterOfProperty(Params.NewNode) then begin
// continue searching of getter
Params.Identifier := @Src[CurPos.StartPos];
end;
ContextNode := Params.NewNode;
Exit(False);
end else
Params.AddOperandPart(GetIdentifier(Params.Identifier));
end;
ctnProcedure:
begin
Params.AddOperandPart(ExtractProcName(Params.NewNode,[]));
// ToDo: add default parameters
end;
end;
if CallOnIdentifierFound then begin
{debugln(['[TFindDeclarationTool.FindIdentifierInContext.CheckResult] CallOnIdentifierFound Ident=',
'"',GetIdentifier(Params.Identifier),'"',
' StartContext="',StartContextNode.DescAsString,'" "',copy(Src,StartContextNode.StartPos,20),'"',
' File="',ExtractFilename(MainFilename)+'"',
' Flags=[',dbgs(Flags),']'
]);}
IdentFoundResult:=Params.NewCodeTool.DoOnIdentifierFound(Params,
Params.NewNode);
{$IFDEF ShowProcSearch}
DebugLn(['[TFindDeclarationTool.FindIdentifierInContext.CheckResult] DoOnIdentifierFound=',IdentifierFoundResultNames[IdentFoundResult]]);
{$ENDIF}
if (IdentFoundResult=ifrSuccess) then
CacheResult(true,ContextNode);
Result:=IdentFoundResult<>ifrProceedSearch;
if IdentFoundResult<>ifrAbortSearch then exit;
end else begin
if fdfCollect in Flags then
Result:=false;
CacheResult(true,ContextNode);
Result:=IdentFoundResult<>ifrProceedSearch;
if IdentFoundResult<>ifrAbortSearch then exit;
end else begin
exit;
end;
end;
if Params.FoundProc<>nil then begin
// there was a proc,
// either the search for the overloaded proc was unsuccessful
// or the searched proc was found in a recursive sub search
// -> return the found proc
if Params.FoundProc^.CacheValid
and (Params.FoundProc^.ProcCompatibility=tcExact) then begin
// stop the search
Result:=true;
end;
FindIdentifierInContext:=true;
{$IFDEF ShowCollect}
if fdfCollect in Flags then
Result:=false;
CacheResult(true,ContextNode);
raise Exception.Create('fdfCollect must never return true');
{$ENDIF}
Params.SetResult(Params.FoundProc^.Context.Tool,
Params.FoundProc^.Context.Node);
{$IF defined(ShowProcSearch) or defined(ShowFoundIdentifier)}
DebugLn('[TFindDeclarationTool.FindIdentifierInContext] PROC Search ended with only one proc (normal when searching every used unit):');
Params.WriteDebugReport;
{$ENDIF}
exit;
end;
end;
if Params.FoundProc<>nil then begin
// there was a proc,
// either the search for the overloaded proc was unsuccessful
// or the searched proc was found in a recursive sub search
// -> return the found proc
if Params.FoundProc^.CacheValid
and (Params.FoundProc^.ProcCompatibility=tcExact) then begin
// stop the search
Result:=true;
// identifier was not found
if not (fdfExceptionOnNotFound in Flags) then exit;
if (Params.Identifier<>nil)
and not (fdfExceptionOnPredefinedIdent in Flags)
and WordIsPredefinedIdentifier.DoItCaseInsensitive(Params.Identifier)
then begin
Params.SetResult(nil,nil);
exit;
end;
// identifier was not found and exception is wanted
// -> raise exception
if Params.IdentifierTool.IsPCharInSrc(Params.Identifier) then
Params.IdentifierTool.MoveCursorToCleanPos(Params.Identifier);
RaiseNotFound;
finally
if FindIdentifierInContext and (Params.NewNode <> nil) and (Params.NewNode.Desc=ctnGenericParameter) then begin
FindIdentifierInContext := Params.FindGenericParamType;
end;
FindIdentifierInContext:=true;
{$IFDEF ShowCollect}
if fdfCollect in Flags then
raise Exception.Create('fdfCollect must never return true');
{$ENDIF}
Params.SetResult(Params.FoundProc^.Context.Tool,
Params.FoundProc^.Context.Node);
{$IF defined(ShowProcSearch) or defined(ShowFoundIdentifier)}
DebugLn('[TFindDeclarationTool.FindIdentifierInContext] PROC Search ended with only one proc (normal when searching every used unit):');
Params.WriteDebugReport;
{$ENDIF}
exit;
end;
// identifier was not found
if not (fdfExceptionOnNotFound in Flags) then exit;
if (Params.Identifier<>nil)
and not (fdfExceptionOnPredefinedIdent in Flags)
and WordIsPredefinedIdentifier.DoItCaseInsensitive(Params.Identifier)
then begin
Params.SetResult(nil,nil);
exit;
end;
// identifier was not found and exception is wanted
// -> raise exception
if Params.IdentifierTool.IsPCharInSrc(Params.Identifier) then
Params.IdentifierTool.MoveCursorToCleanPos(Params.Identifier);
RaiseNotFound;
end;
procedure MoveContextNodeToChildren;
@ -5326,9 +5291,6 @@ var
ReadNextAtom; // read AUnitName
SaveRaiseCharExpectedButAtomFound(20170421200146,'.');
end;
if TypeFound and (SubParams.NewNode.Desc=ctnGenericParameter) then begin
TypeFound:=SubParams.FindGenericParamType;
end;
if TypeFound then begin
// only types allowed here
TestContext.Tool:=SubParams.NewCodeTool;
@ -5645,7 +5607,6 @@ begin
Result.Node:=NameNode;
if Result.Node=nil then break;
Params.SetGenericParamValues(Self, SpecializeNode);
Params.UpdateGenericParamMapping(Self, SpecializeNode.FirstChild.NextBrother, Nil);
SearchIdentifier(SpecializeNode,NameNode.StartPos,IsPredefined,Result);
if (Result.Node=nil) or (Result.Node.Desc<>ctnGenericType) then begin
// not a generic
@ -7608,7 +7569,7 @@ function TFindDeclarationTool.FindAncestorOfClassInheritance(
var
InheritanceNode: TCodeTreeNode;
ClassNode: TCodeTreeNode;
SpecializeNode , GenericParamsNode: TCodeTreeNode;
SpecializeNode: TCodeTreeNode;
AncestorContext: TFindContext;
AncestorStartPos: LongInt;
ExprType: TExpressionType;
@ -7653,6 +7614,7 @@ begin
Params:=TFindDeclarationParams.Create(ResultParams);
try
Params.GenParams := ResultParams.GenParams;
Params.Flags:=fdfDefaultForExpressions;
Params.ContextNode:=IdentifierNode;
if CurPos.Flag=cafPoint then begin
@ -7677,14 +7639,6 @@ begin
if not FindIdentifierInContext(Params) then
exit;
if (Params.NewNode.Desc in [ctnGenericParameter]) then
begin
Params.GenParams := ResultParams.GenParams;
if not Params.FindGenericParamType then
if not FindClassFromGenericParamType(Params.NewNode, Params) then
exit;
end;
AncestorContext.Tool:=Params.NewCodeTool;
AncestorContext.Node:=Params.NewNode;
end;
@ -7697,16 +7651,10 @@ begin
if (AncestorContext.Node.Desc in [ctnTypeDefinition,ctnGenericType]) then
begin
Params:=TFindDeclarationParams.Create;
Params.GenParams := ResultParams.GenParams;
if IdentifierNode.Desc=ctnSpecialize then begin
SpecializeNode:=IdentifierNode;
Params.SetGenericParamValues(Self, SpecializeNode);
if (ClassNode <> nil) then begin
GenericParamsNode := nil;
if (ClassNode.Parent <> nil)
and (ClassNode.Parent.Desc = ctnGenericType) then
GenericParamsNode:=ClassNode.Parent.FirstChild.NextBrother;
ResultParams.UpdateGenericParamMapping(Self, SpecializeNode.FirstChild.NextBrother, GenericParamsNode);
end;
end;
try
Params.Flags:=fdfDefaultForExpressions+[fdfFindChildren];
@ -9845,10 +9793,6 @@ var
end else if ExprType.Context.Node.Desc in AllPointContexts then begin
// ok, allowed
break;
end else if ExprType.Context.Node.Desc = ctnGenericParameter then begin
// ok, allowed
if not Params.UpdateContexWithGenParamValue(ExprType.Context) then
RaiseIllegalQualifierFound(20210924170159);
end else begin
// not allowed
//debugln(['ResolvePoint ',ExprTypeToString(ExprType)]);
@ -10298,8 +10242,7 @@ begin
ResolveChildren;
Result:=ExprType;
if (Result.Desc=xtContext) and (not (fdfFindVariable in StartFlags))
and (not (Result.Context.Node.Desc = ctnSpecialize)) then
if (Result.Desc=xtContext) and (not (fdfFindVariable in StartFlags)) then
Result:=Result.Context.Tool.ConvertNodeToExpressionType(
Result.Context.Node,Params);
{$IFDEF ShowExprEval}
@ -12825,17 +12768,13 @@ function TFindDeclarationTool.FindForInTypeAsString(TermPos: TAtomPosition;
xtContext:
begin
case SubExprType.Context.Node.Desc of
ctnSpecialize, ctnClass, ctnRecordType, ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnClassInterface:
ctnClass, ctnRecordType, ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnClassInterface:
begin
AliasType:=CleanFindContext;
if not SubExprType.Context.Tool.FindEnumeratorOfClass(
SubExprType.Context.Node,true,ExprType,@AliasType, Params)
then
RaiseTermHasNoIterator(20170421211210,SubExprType);
if (ExprType.Desc = xtContext)
and (ExprType.Context.Node.Desc = ctnGenericParameter) then begin
Params.UpdateContexWithGenParamValue(ExprType.Context);
end;
Result:=FindExprTypeAsString(ExprType,TermPos.StartPos,@AliasType);
end;
ctnEnumerationType:
@ -12988,6 +12927,7 @@ begin
AliasType^:=CleanFindContext;
ExprType:=CleanExpressionType;
Params:=TFindDeclarationParams.Create(ParentParams);
Params.GenParams := ParentParams.GenParams;
try
if ClassNode.Desc = ctnSpecialize then begin
Params.ContextNode:=ClassNode;
@ -13264,9 +13204,10 @@ begin
if (ArrayNode.Parent <> nil)
and (ArrayNode.Parent.Desc = ctnGenericType)
and (ParentParams <> nil) then begin
// TODO: make sure there is ONLY ONE GenParam
ExprType.Desc := xtContext;
ExprType.Context.Node := ParentParams.GenParamValueMappings.SpecializeParamsNode.FirstChild;
ExprType.Context.Tool := ParentParams.GenParamValueMappings.SpecializeParamsTool;
ExprType.Context.Node := ParentParams.GenParams.SpecializeParamsNode.FirstChild;
ExprType.Context.Tool := ParentParams.GenParams.ParamValuesTool;
Result:=true;
end else begin
MoveCursorToNodeStart(ArrayNode);
@ -13281,6 +13222,7 @@ begin
ReadNextAtom;
if not AtomIsIdentifier then exit;
Params:=TFindDeclarationParams.Create;
Params.GenParams := ParentParams.GenParams;
try
Params.Flags:=fdfDefaultForExpressions;
Params.ContextNode:=ArrayNode;
@ -13743,43 +13685,6 @@ begin
end;
end;
function TFindDeclarationTool.FindClassFromGenericParamType(
GenParamNode: TCodeTreeNode; ResultParams: TFindDeclarationParams): boolean;
var
Params: TFindDeclarationParams;
TmpNode: TCodeTreeNode;
begin
Result := False;
if (ResultParams = nil) or (GenParamNode.Desc <> ctnGenericParameter)
or (GenParamNode.Parent = nil) // or (GenParamNode.Parent.Parent = nil)
or (GenParamNode.LastChild = nil)
then
exit;
Result := True;
Params:=TFindDeclarationParams.Create(Self, GenParamNode.Parent);
try
Params.Flags:=fdfDefaultForExpressions;
Params.SetIdentifier(Self,@Src[GenParamNode.LastChild.StartPos],nil);
if not FindIdentifierInContext(Params) then
RaiseUnexpectedKeyWord(0);
ResultParams.NewCodeTool:=Params.NewCodeTool;
ResultParams.NewNode:=Params.NewNode;
Include(ResultParams.Flags,fdfDoNotCache);
finally
Params.Free;
end;
if ResultParams.NewNode.Desc in [ctnTypeDefinition] then begin
TmpNode:=ResultParams.NewCodeTool.FindTypeNodeOfDefinition(ResultParams.NewNode);
if (TmpNode<>nil)
then
ResultParams.NewNode := TmpNode;
Include(ResultParams.Flags,fdfDoNotCache);
end;
end;
function TFindDeclarationTool.FindExtendedExprOfHelper(HelperNode: TCodeTreeNode
): TExpressionType;
// returns the expression type of the extended class/type of a "helper for"
@ -13914,7 +13819,6 @@ begin
for HelperKind in TFDHelpersListKind do
if FFreeHelpers[HelperKind] then
FreeAndNil(FHelpers[HelperKind]);
GenParamValueMappings.FirstParamValueMapping.Free;
inherited Destroy;
end;
@ -14123,133 +14027,27 @@ end;
procedure TFindDeclarationParams.SetGenericParamValues(
SpecializeParamsTool: TFindDeclarationTool;
SpecializeNode: TCodeTreeNode);
var
GenP: TGenericParams;
begin
if (GenParams.SpecializeParamsNode <> nil) then begin
GenP := GenParams;
SetLength(GenParams.OuterGenParam, 1);
GenParams.OuterGenParam[0] := GenP;
end
else
SetLength(GenParams.OuterGenParam, 0);
GenParams.ParamValuesTool := SpecializeParamsTool;
GenParams.SpecializeParamsNode := SpecializeNode.FirstChild.NextBrother;
end;
procedure TFindDeclarationParams.UpdateGenericParamMapping(SpecializeParamsTool: TFindDeclarationTool;
SpecializeParamsNode: TCodeTreeNode; GenericParamsNode: TCodeTreeNode);
procedure ForwardParamMapping;
var
lGenericParamNode,
lSpecializeParamNode,
lGenericParamValueNode: TCodeTreeNode;
lFirstMapping,
lMapping,
lLoopMapping: TGenericParamValueMapping;
lFound: Boolean;
begin
lFirstMapping := nil;
lMapping := nil;
// GenericParams: GObject1<V1, V2> = class(GObject2<V2, V1>)
// ^^^^^^
// SpecializeParams: GObject1<V1, V2> = class(GObject2<V2, V1>)
// ^^^^^^
if GenParamValueMappings.FirstParamValueMapping = nil then begin
// first mapping: values from GenParamValueMappings.SpecializeParamsNode
lSpecializeParamNode := SpecializeParamsNode.FirstChild;
while lSpecializeParamNode <> nil do begin
//find generic param / generic param value
lGenericParamNode := GenericParamsNode.FirstChild;
lGenericParamValueNode := GenParamValueMappings.SpecializeParamsNode.FirstChild;
lFound := false;
while (lGenericParamNode <> nil)
and (lGenericParamValueNode <> nil) do begin
if SpecializeParamsTool.CompareSrcIdentifiers(lSpecializeParamNode.StartPos, lGenericParamNode.StartPos) then begin
// found generic param
lMapping := TGenericParamValueMapping.Create(lMapping, lSpecializeParamNode, lGenericParamValueNode);
if lFirstMapping = nil then
lFirstMapping := lMapping;
lFound := true;
break;
end;
lGenericParamNode := lGenericParamNode.NextBrother;
lGenericParamValueNode := lGenericParamValueNode.NextBrother;
end;
if not lFound then begin
end;
lSpecializeParamNode := lSpecializeParamNode.NextBrother;
end;
GenParamValueMappings.FirstParamValueMapping := lFirstMapping;
GenParamValueMappings.SpecializeValuesTool := GenParamValueMappings.SpecializeParamsTool;
end else begin
// further mapping: values from GenParamValueMappings.FirstParamValueMapping
lSpecializeParamNode := SpecializeParamsNode.FirstChild;
while lSpecializeParamNode <> nil do begin
//find generic param / generic param value
lLoopMapping := GenParamValueMappings.FirstParamValueMapping;
lGenericParamNode := GenericParamsNode.FirstChild;
lFound := false;
while (lLoopMapping <> nil) do begin
lGenericParamValueNode := lLoopMapping.SpecializeValueNode;
if SpecializeParamsTool.CompareSrcIdentifiers(lSpecializeParamNode.StartPos, lGenericParamNode.StartPos) then begin
// found generic param
lMapping := TGenericParamValueMapping.Create(lMapping, lSpecializeParamNode, lGenericParamValueNode);
if lFirstMapping = nil then
lFirstMapping := lMapping;
lFound := true;
break;
end;
lGenericParamNode := lGenericParamNode.NextBrother;
lLoopMapping := lLoopMapping.NextBrother;
end;
if not lFound then begin
end;
lSpecializeParamNode := lSpecializeParamNode.NextBrother;
end;
GenParamValueMappings.FirstParamValueMapping.Free;
GenParamValueMappings.FirstParamValueMapping := lFirstMapping;
end;
end;
begin
if Parent <> nil then begin
Parent.UpdateGenericParamMapping(SpecializeParamsTool, SpecializeParamsNode, GenericParamsNode);
exit;
end;
if (GenericParamsNode <> nil)
and (GenParamValueMappings.SpecializeParamsNode <> nil) then
ForwardParamMapping;
GenParamValueMappings.SpecializeParamsTool := SpecializeParamsTool;
GenParamValueMappings.SpecializeParamsNode := SpecializeParamsNode;
end;
function TFindDeclarationParams.UpdateContexWithGenParamValue(
var SpecializeParamContext: TFindContext): Boolean;
var
lMapping: TGenericParamValueMapping;
lPNode, lVNode: TCodeTreeNode;
lPTool, lVTool: TFindDeclarationTool;
begin
Result := False;
if Assigned(Parent) then begin
Result := Parent.UpdateContexWithGenParamValue(SpecializeParamContext);
exit;
end;
lMapping := GenParamValueMappings.FirstParamValueMapping;
while lMapping <> nil do begin
lPNode := lMapping.GenericParamNode;
lPTool := GenParamValueMappings.SpecializeParamsTool;
lVNode := lMapping.SpecializeValueNode;
lVTool := GenParamValueMappings.SpecializeValuesTool;
if SpecializeParamContext.Tool.CompareSrcIdentifiers(SpecializeParamContext.Node.StartPos, @lPTool.Src[lPNode.StartPos]) then begin
Result := True;
SpecializeParamContext.Node := lVNode;
SpecializeParamContext.Tool := lVTool;
exit;
end;
lMapping := lMapping.NextBrother;
end;
end;
function TFindDeclarationParams.FindGenericParamType: Boolean;
var
i, n: integer;
GenParamType: TCodeTreeNode;
OldGenParam: TGenericParams;
begin
// NewCodeTool, NewNode=GenericParamType
if not Assigned(NewCodeTool) or not Assigned(NewNode)
@ -14283,7 +14081,15 @@ begin
Identifier:=@Src[CurPos.StartPos];
IdentifierTool:=GenParams.ParamValuesTool;
ContextNode:=GenParams.SpecializeParamsNode;
OldGenParam := GenParams;
if Length(GenParams.OuterGenParam) > 0 then
GenParams := GenParams.OuterGenParam[0]
else begin
GenParams.ParamValuesTool:=nil;
GenParams.SpecializeParamsNode:=nil;
end;
Result:=FindIdentifierInContext(Self);
GenParams := OldGenParam;
end;
end;

View File

@ -1,209 +0,0 @@
program generic_base;
{$mode objfpc}{$H+}
uses
Classes;
type
{ TBase }
TBase = class
procedure BaseProc;
procedure BaseProc2; virtual; abstract;
end;
{ TSubBase }
TSubBase = class(TBase)
procedure BaseProc; reintroduce;
procedure BaseProc2; virtual; abstract;
end;
{ TFoo1 }
TFoo1 = class(TStream)
procedure Foo;
end;
{ TFoo2 }
TFoo2 = class(TStream)
procedure Foo;
end;
{ TBar }
TBar = class(TStream)
procedure Bar;
end;
{ TGen1 }
generic TGen1<Base: TObject; _B> = class(Base)
procedure GenBar(P1: _B);
end;
{ TGen2 }
generic TGen2<_B; _X, Base: TObject> = class(Base)
procedure GenBar(P1: _B; P2: _X);
end;
{ TGen3 }
generic TGen3<_B; Base: TBase> = class(Base)
procedure GenBar(P1: _B);
procedure BaseProc2{declaration:TBase.BaseProc2}; reintroduce; virtual; abstract;
end;
generic TGenGen1<XBase: TObject; _BB> = class(specialize TGen1<XBase, _BB>)
end;
TSpec1Foo1 = specialize TGen1<TFoo1, TPoint>;
TSpec1Foo2 = specialize TGen1<TFoo2, TPoint>;
TSpec2Foo1 = specialize TGen2<Integer, TBase, TFoo1>;
TSpecGG1Foo1 = specialize TGenGen1<TFoo1, TPoint>;
//TSpec3Foo1 = specialize TGen2<Integer, TPoint, TFoo1>;
{ TSpec1ClsFoo1 }
TSpec1ClsFoo1 = class(specialize TGen1<TFoo1, TPoint>)
procedure Spec1a;
end;
TSpec1ClsFoo1X = class(specialize TGen1<TFoo1, TPoint>)
procedure Foo{declaration:TFoo1.Foo}; virtual; abstract;
end;
{ TSpec1ClsFoo2 }
TSpec1ClsFoo2 = class(specialize TGen1<TFoo2, TPoint>)
procedure Spec1a;
end;
TSpec1ClsFoo2X = class(specialize TGen1<TFoo2, TPoint>)
procedure Foo{declaration:TFoo2.Foo}; virtual; abstract;
end;
{ TSpec3ClsSubBase }
TSpec3ClsSubBase = class(specialize TGen3<TBase, TSubBase>)
procedure Spec1a;
end;
{ TBase }
procedure TBase.BaseProc;
begin
end;
{ TSubBase }
procedure TSubBase.BaseProc;
begin
end;
{ TSpec1ClsFoo2 }
procedure TSpec1ClsFoo2.Spec1a;
begin
//
end;
{ TFoo1 }
procedure TFoo1.Foo;
var
s1f1: TSpec1Foo1;
s1f2: TSpec1Foo2;
s1CF1: TSpec1ClsFoo1;
s1CF2: TSpec1ClsFoo2;
s2f1: TSpec2Foo1;
sgg1f1: TSpecGG1Foo1;
s1x: specialize TGen1<TFoo1, TRect>;
begin
s1f1.Foo{declaration:TFoo1.Foo};
s1f2.Foo{declaration:TFoo2.Foo};
s1CF1.Foo{declaration:TFoo1.Foo};
s1CF2.Foo{declaration:TFoo2.Foo};
s2f1.Foo{declaration:TFoo1.Foo};
sgg1f1.Foo{ TODO declaration:TFoo1.Foo};
s1x.Foo{declaration:TFoo1.Foo};
end;
{ TFoo2 }
procedure TFoo2.Foo;
begin
end;
{ TBar }
procedure TBar.Bar;
begin
end;
{ TGen1 }
procedure TGen1.GenBar(P1: _B);
begin
end;
{ TGen2 }
procedure TGen2.GenBar(P1: _B; P2: _X);
begin
end;
{ TGen3 }
procedure TGen3.GenBar(P1: _B);
begin
BaseProc{declaration:TBase.BaseProc};
end;
{ TSpec1ClsFoo1 }
procedure TSpec1ClsFoo1.Spec1a;
begin
inherited foo{declaration:TFoo1.Foo};
foo{declaration:TFoo1.Foo};
end;
{ TSpec3ClsSubBase }
procedure TSpec3ClsSubBase.Spec1a;
begin
end;
var
g1: TSpec1Foo1;
g1a: TSpec1ClsFoo1;
g1x: specialize TGen1<TFoo1, TRect>;
s3: TSpec3ClsSubBase;
begin
g1a.Foo{declaration:TFoo1.Foo};
g1.Foo{declaration:TFoo1.Foo};
s3.BaseProc{declaration:TSubBase.BaseProc};
end.

File diff suppressed because it is too large Load Diff