diff --git a/components/codetools/codecompletiontool.pas b/components/codetools/codecompletiontool.pas index 2b1c9cff80..6c2bac40cf 100644 --- a/components/codetools/codecompletiontool.pas +++ b/components/codetools/codecompletiontool.pas @@ -1373,10 +1373,10 @@ begin // save cursor OldCursor:=CurPos; // search identifier - if Params=nil then - Params:=TFindDeclarationParams.Create; if ContextNode=nil then ContextNode:=FindDeepestNodeAtPos(CurPos.StartPos,true); + if Params=nil then + Params:=TFindDeclarationParams.Create(Self, ContextNode); ContextNode := ContextNode.GetNodeOfType(ctnProcedureType); Params.ContextNode:=ContextNode; Params.SetIdentifier(Self,@Src[CurPos.StartPos],@CheckSrcIdentifier); @@ -1656,7 +1656,7 @@ begin // search variable ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try {$IFDEF VerboseCompleteLocalVarAssign} DebugLn(' CompleteLocalVariableAssignment: check if variable is already defined ...'); @@ -1685,7 +1685,7 @@ begin begin Params.SetIdentifier(Self, PChar(NewType), nil); Params.ContextNode := CursorNode; - Params.Flags := [fdfSearchInAncestors..fdfIgnoreCurContextNode]; + Params.Flags := [fdfSearchInAncestors..fdfIgnoreCurContextNode,fdfSearchInHelpers]; if FindIdentifierInContext(Params) and (Params.NewCodeTool <> ExprType.Context.Tool) then NewType := ExprType.Context.Tool.ExtractSourceName + '.' + NewType; @@ -1791,7 +1791,7 @@ var Params.SetIdentifier(Self,@Src[CurPos.StartPos],nil); fFullTopLvlName:=''; Params.OnTopLvlIdentifierFound:=@OnTopLvlIdentifierFound; - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfTopLvlResolving,fdfFindVariable]; if (not FindDeclarationOfIdentAtParam(Params)) then begin {$IFDEF CTDEBUG} @@ -1808,7 +1808,7 @@ var PropVarContext:=CreateFindContext(Params); // identifier is property // -> check type of property - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors]; + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers]; ProcContext:=PropVarContext.Tool.FindBaseTypeOfNode( Params,PropVarContext.Node); if (ProcContext.Node=nil) or (ProcContext.Node.Desc<>ctnProcedureType) @@ -1979,7 +1979,7 @@ begin {$ENDIF} FindProcAndClassNode(ProcNode,AClassNode); - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try {$IFDEF VerboseCompleteEventAssign} DebugLn(' CompleteEventAssignment: FindEventTypeAtCursor...'); @@ -2091,7 +2091,7 @@ begin // search variable ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try {$IFDEF CTDEBUG} DebugLn(' CompleteLocalVariableForIn: check if variable is already defined ...'); @@ -2242,7 +2242,7 @@ begin {$ENDIF} // search variable - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try {$IFDEF CTDEBUG} DebugLn(' CompleteLocalIdentifierByParameter: check if variable is already defined ...'); @@ -2270,40 +2270,54 @@ begin Params.ContextNode:=Context.Node; Params.Flags:=fdfDefaultForExpressions+[fdfFunctionResult,fdfFindChildren]; ExprType:=FindExpressionResultType(Params,ProcStartPos,ProcNameAtom.StartPos); - if ExprType.Desc<>xtContext then begin + if not(ExprType.Desc in xtAllIdentTypes) then begin debugln(['TCodeCompletionCodeTool.CompleteLocalIdentifierByParameter Call="',ExtractCode(ProcStartPos,ProcNameAtom.StartPos,[]),'" gives ',ExprTypeToString(ExprType)]); exit; end; - // resolve point '.' Context:=ExprType.Context; - //debugln(['TCodeCompletionCodeTool.CompleteLocalIdentifierByParameter base class: ',FindContextToString(Context)]); - Params.Clear; - Params.Flags:=fdfDefaultForExpressions; - Context:=Context.Tool.FindBaseTypeOfNode(Params,Context.Node); - {$IFDEF CTDEBUG} - debugln(['TCodeCompletionCodeTool.CompleteLocalVariableByParameter search proc in sub context: ',FindContextToString(Context)]); - {$ENDIF} + if Assigned(Context.Tool) and Assigned(Context.Node) then + begin + // resolve point '.' + //debugln(['TCodeCompletionCodeTool.CompleteLocalIdentifierByParameter base class: ',FindContextToString(Context)]); + Params.Clear; + Params.Flags:=fdfDefaultForExpressions; + Context:=Context.Tool.FindBaseTypeOfNode(Params,Context.Node); + {$IFDEF CTDEBUG} + debugln(['TCodeCompletionCodeTool.CompleteLocalVariableByParameter search proc in sub context: ',FindContextToString(Context)]); + {$ENDIF} + end; + end; + if Assigned(Context.Tool) and Assigned(Context.Node) then + begin + // find declaration of parameter list + // ToDo: search in all overloads for the best fit + Params.ContextNode:=Context.Node; + Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],nil); + Params.Flags:=fdfDefaultForExpressions+[fdfFindVariable]; + if Context.Node=CursorNode then + Params.Flags:=Params.Flags+[fdfSearchInParentNodes,fdfIgnoreCurContextNode] + else + Params.Flags:=Params.Flags-[fdfSearchInParentNodes,fdfIgnoreCurContextNode]; + CleanPosToCodePos(VarNameRange.StartPos,IgnorePos); + IgnoreErrorAfter:=IgnorePos; + try + {$IFDEF CTDEBUG} + debugln(['TCodeCompletionCodeTool.CompleteLocalIdentifierByParameter searching ',GetIdentifier(Params.Identifier),' [',dbgs(Params.Flags),'] in ',FindContextToString(Context)]); + {$ENDIF} + if not Context.Tool.FindIdentifierInContext(Params) then exit; + finally + ClearIgnoreErrorAfter; + end; + end else + if (ExprType.Desc in xtAllIdentPredefinedTypes) then + begin + Params.ContextNode:=CursorNode; + Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],nil); + Params.Flags:=fdfDefaultForExpressions+[fdfFindVariable]+ + [fdfSearchInParentNodes,fdfIgnoreCurContextNode]; + FindIdentifierInBasicTypeHelpers(ExprType.Desc, Params); end; - // find declaration of parameter list - // ToDo: search in all overloads for the best fit - Params.ContextNode:=Context.Node; - Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],nil); - Params.Flags:=fdfDefaultForExpressions+[fdfFindVariable]; - if Context.Node=CursorNode then - Params.Flags:=Params.Flags+[fdfSearchInParentNodes,fdfIgnoreCurContextNode] - else - Params.Flags:=Params.Flags-[fdfSearchInParentNodes,fdfIgnoreCurContextNode]; - CleanPosToCodePos(VarNameRange.StartPos,IgnorePos); - IgnoreErrorAfter:=IgnorePos; - try - {$IFDEF CTDEBUG} - debugln(['TCodeCompletionCodeTool.CompleteLocalIdentifierByParameter searching ',GetIdentifier(Params.Identifier),' [',dbgs(Params.Flags),'] in ',FindContextToString(Context)]); - {$ENDIF} - if not Context.Tool.FindIdentifierInContext(Params) then exit; - finally - ClearIgnoreErrorAfter; - end; NewType:=''; MissingUnitName:=''; if Params.NewNode=nil then exit; @@ -2329,7 +2343,7 @@ begin // search type Params.Clear; Params.ContextNode:=TypeNode; - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfTopLvlResolving]; AliasType:=CleanFindContext; ExprType:=TypeTool.FindExpressionResultType(Params, @@ -2682,7 +2696,7 @@ begin ExprList:=nil; ParamNames:=nil; ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try // check parameter list Params.ContextNode:=CursorNode; @@ -2813,7 +2827,7 @@ const Params.ContextNode:=CursorNode; Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],@CheckSrcIdentifier); Params.Flags:=[fdfSearchInParentNodes, - fdfTopLvlResolving,fdfSearchInAncestors, + fdfTopLvlResolving,fdfSearchInAncestors,fdfSearchInHelpers, fdfIgnoreCurContextNode]; if FindIdentifierInContext(Params) then begin // proc already exists @@ -2953,7 +2967,7 @@ begin CheckWholeUnitParsed(CursorNode,BeginNode); Beauty:=SourceChangeCache.BeautifyCodeOptions; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); ExprList:=nil; ActivateGlobalWriteLock; try @@ -5332,6 +5346,7 @@ function TCodeCompletionCodeTool.BuildUnitDefinitionGraph(out end; ctnClassInterface, ctnDispinterface, ctnClass, ctnObject, ctnRecordType, + ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnObjCClass, ctnObjCCategory, ctnObjCProtocol, ctnCPPClass: begin ChildNode:=SubNode.FirstChild; @@ -5799,7 +5814,7 @@ function TCodeCompletionCodeTool.FindAssignMethod(CursorPos: TCodeXYPosition; Params: TFindDeclarationParams; begin if ClassNode=nil then exit; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, ClassNode); try Params.Flags:=[fdfSearchInAncestors]; Params.Identifier:=PChar(ProcName); @@ -6074,11 +6089,11 @@ begin Result:=true; end; if VarNode=nil then begin - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try Params.ContextNode:=CursorNode; Params.SetIdentifier(Self,Identifier,nil); - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfTopLvlResolving,fdfFindVariable]; Result:=FindIdentifierInContext(Params); VarTool:=Params.NewCodeTool; @@ -6099,7 +6114,7 @@ begin end; // resolve type - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try Params.Flags:=fdfDefaultForExpressions; if VarNode.Desc in [ctnProcedure,ctnProcedureHead] then @@ -6143,7 +6158,7 @@ begin AddAssignment('nil'); ctnProcedureHead: if Tool.NodeIsFunction(Node) then begin - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, Node); try aContext:=Tool.FindBaseTypeOfNode(Params,Node); Tool:=aContext.Tool; @@ -6284,7 +6299,7 @@ begin // search identifier ActivateGlobalWriteLock; try - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try {$IFDEF CTDEBUG} DebugLn(' GuessTypeOfIdentifier: check if variable is already defined ...'); @@ -6361,7 +6376,7 @@ begin debugln(['TCodeCompletionCodeTool.GuessTypeOfIdentifier guessing type of assignment :="',dbgstr(Src,TermAtom.StartPos,TermAtom.EndPos-TermAtom.StartPos),'"']); // find type of term - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try Params.ContextNode:=CursorNode; NewType:=FindTermTypeAsString(TermAtom,Params,NewExprType); @@ -6392,7 +6407,7 @@ begin debugln(['TCodeCompletionCodeTool.GuessTypeOfIdentifier guessing type of for-in list "',dbgstr(Src,TermAtom.StartPos,TermAtom.EndPos-TermAtom.StartPos),'"']); // find type of term - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try NewType:=FindForInTypeAsString(TermAtom,CursorNode,Params,NewExprType); finally diff --git a/components/codetools/codetoolsstrconsts.pas b/components/codetools/codetoolsstrconsts.pas index dfc16a45dd..449e2db36b 100644 --- a/components/codetools/codetoolsstrconsts.pas +++ b/components/codetools/codetoolsstrconsts.pas @@ -82,6 +82,7 @@ ResourceString crsFoundUnexpectedAt = '%s, found unexpected %s at %s'; ctsAnonymDefinitionsAreNotAllowed = 'Anonymous %s definitions are not allowed'; ctsNestedDefinitionsAreNotAllowed = 'Nested %s definitions are not allowed'; + ctsHelperIsNotAllowed = 'Helper after %s is not allowed'; ctsEndForRecordNotFound = 'end for record not found'; ctsMissingEnumList = 'missing enum list'; ctsMissingTypeIdentifier = 'missing type identifier'; diff --git a/components/codetools/codetree.pas b/components/codetools/codetree.pas index 158cfb078b..55a04cfdf0 100644 --- a/components/codetools/codetree.pas +++ b/components/codetools/codetree.pas @@ -91,14 +91,15 @@ const ctnObjCCategory = 35; ctnObjCProtocol = 36; ctnCPPClass = 37; - ctnTypeHelper = 38; + ctnTypeHelper = 38;//"type helper" + ctnRecordHelper = 39;//"record helper" ctnClassAbstract = 40; ctnClassSealed = 41; ctnClassExternal = 42; - ctnClassHelper = 43; + ctnClassHelper = 43;//"class helper" ctnClassInheritance = 44; - ctnClassHelperFor = 45; + ctnHelperFor = 45;//class/record/type helper for ctnClassGUID = 46; ctnClassClassVar = 47; // child of visibility section ctnClassPrivate = 48; // child of AllClassObjects @@ -167,9 +168,10 @@ const [ctnConstSection, ctnTypeSection, ctnVarSection, ctnClassClassVar]; AllClassSections = AllClassBaseSections+AllClassSubSections; - AllClassInterfaces = [ctnClassInterface,ctnDispinterface,ctnObjCProtocol,ctnTypeHelper]; + AllClassInterfaces = [ctnClassInterface,ctnDispinterface,ctnObjCProtocol]; AllClassObjects = [ctnClass,ctnObject,ctnRecordType, - ctnObjCClass,ctnObjCCategory,ctnCPPClass]; + ctnObjCClass,ctnObjCCategory,ctnCPPClass, + ctnClassHelper,ctnRecordHelper,ctnTypeHelper]; AllClasses = AllClassObjects+AllClassInterfaces; AllClassModifiers = [ctnClassAbstract, ctnClassSealed, ctnClassExternal]; AllDefinitionSections = @@ -192,7 +194,7 @@ const ctnInitialization,ctnFinalization]; AllFindContextDescs = AllIdentifierDefinitions + AllCodeSections + AllClasses + [ctnProcedure]; - AllPointContexts = AllClasses+AllSourceTypes+[ctnEnumerationType,ctnInterface,ctnImplementation]; + AllPointContexts = AllClasses+AllSourceTypes+[ctnEnumerationType,ctnInterface,ctnImplementation,ctnTypeType]; // CodeTreeNodeSubDescriptors @@ -367,6 +369,7 @@ begin ctnObjCProtocol: Result:='ObjCProtocol'; ctnCPPClass: Result:='CPPClass'; ctnTypeHelper: Result:='Type Helper'; + ctnRecordHelper: Result:='Record Helper'; ctnClassInheritance: Result:='Class inheritance'; ctnClassGUID: Result:='GUID'; @@ -380,8 +383,8 @@ begin ctnClassAbstract: Result:='abstract'; ctnClassSealed: Result:='sealed'; ctnClassExternal: Result:='external'; - ctnClassHelper: Result:='helper'; - ctnClassHelperFor: Result:='(helper) for'; + ctnClassHelper: Result:='Class Helper'; + ctnHelperFor: Result:='(helper) for'; ctnProcedure: Result:='Procedure'; ctnProcedureHead: Result:='ProcedureHead'; diff --git a/components/codetools/customcodetool.pas b/components/codetools/customcodetool.pas index 1883b0a735..52ca658a8f 100644 --- a/components/codetools/customcodetool.pas +++ b/components/codetools/customcodetool.pas @@ -574,7 +574,8 @@ begin if (SubDesc and ctnsNeedJITParsing)>0 then Result:=ctsUnparsed; end; ctnClass,ctnObject,ctnRecordType,ctnObjCClass,ctnObjCCategory,ctnObjCProtocol, - ctnCPPClass,ctnClassInterface,ctnDispinterface: + ctnCPPClass,ctnClassInterface,ctnDispinterface, + ctnTypeHelper,ctnRecordHelper,ctnClassHelper: begin Result:=''; if (SubDesc and ctnsForwardDeclaration)>0 then Result:=ctsForward; diff --git a/components/codetools/eventcodetool.pas b/components/codetools/eventcodetool.pas index 8bd59ebe8a..f786563348 100644 --- a/components/codetools/eventcodetool.pas +++ b/components/codetools/eventcodetool.pas @@ -532,6 +532,7 @@ var var TypeName: string; Params: TFindDeclarationParams; TypeContext: TFindContext; + CLList: THelpersList; begin Result:=CleanFindContext; if AStartUnitName<>'' then begin @@ -545,48 +546,53 @@ begin end; ActivateGlobalWriteLock; - Params:=nil; try - // find method type declaration - TypeName:=ATypeInfo^.Name; - Params:=TFindDeclarationParams.Create; + CLList := THelpersList.Create; try - // find method in interface and used units - Params.ContextNode:=FindImplementationNode; - if Params.ContextNode=nil then - Params.ContextNode:=FindMainBeginEndNode; - if Params.ContextNode=nil then begin - MoveCursorToNodeStart(Tree.Root); - RaiseException(Format(ctsIdentifierNotFound,[GetIdentifier(@TypeName[1])])); + // find method type declaration + TypeName:=ATypeInfo^.Name; + Params:=TFindDeclarationParams.Create(CLList);//FindHelpersInContext will be called later + try + // find method in interface and used units + Params.ContextNode:=FindImplementationNode; + if Params.ContextNode=nil then + Params.ContextNode:=FindMainBeginEndNode; + if Params.ContextNode=nil then begin + MoveCursorToNodeStart(Tree.Root); + RaiseException(Format(ctsIdentifierNotFound,[GetIdentifier(@TypeName[1])])); + end; + FindHelpersInContext(Params); + Params.SetIdentifier(Self,@TypeName[1],nil); + Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInParentNodes]; + //DebugLn(['TEventsCodeTool.FindMethodTypeInfo TypeName=',TypeName,' MainFilename=',MainFilename]); + FindIdentifierInContext(Params); + // find proc node + if Params.NewNode.Desc<>ctnTypeDefinition then begin + Params.NewCodeTool.MoveCursorToNodeStart(Params.NewNode); + Params.NewCodeTool.RaiseException(ctsMethodTypeDefinitionNotFound); + end; + TypeContext:=CreateFindContext(Params); + finally + Params.Free; end; - Params.SetIdentifier(Self,@TypeName[1],nil); - Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInParentNodes]; - //DebugLn(['TEventsCodeTool.FindMethodTypeInfo TypeName=',TypeName,' MainFilename=',MainFilename]); - FindIdentifierInContext(Params); - // find proc node - if Params.NewNode.Desc<>ctnTypeDefinition then begin - Params.NewCodeTool.MoveCursorToNodeStart(Params.NewNode); - Params.NewCodeTool.RaiseException(ctsMethodTypeDefinitionNotFound); - end; - TypeContext:=CreateFindContext(Params); - finally - Params.Free; - end; - Params:=TFindDeclarationParams.Create; - try - Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInParentNodes]; - Result:=TypeContext.Tool.FindBaseTypeOfNode(Params,TypeContext.Node); - if Result.Node=nil then begin - TypeContext.Tool.MoveCursorToNodeStart(TypeContext.Node); - TypeContext.Tool.RaiseException(ctsMethodTypeDefinitionNotFound); - end; - if Result.Node.Desc<>ctnProcedureType then begin - TypeContext.Tool.MoveCursorToNodeStart(TypeContext.Node); - TypeContext.Tool.RaiseException(Format(ctsExpectedAMethodTypeButFound, [ - Result.Node.DescAsString])); + Params:=TFindDeclarationParams.Create(CLList); + try + Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInParentNodes]; + Result:=TypeContext.Tool.FindBaseTypeOfNode(Params,TypeContext.Node); + if Result.Node=nil then begin + TypeContext.Tool.MoveCursorToNodeStart(TypeContext.Node); + TypeContext.Tool.RaiseException(ctsMethodTypeDefinitionNotFound); + end; + if Result.Node.Desc<>ctnProcedureType then begin + TypeContext.Tool.MoveCursorToNodeStart(TypeContext.Node); + TypeContext.Tool.RaiseException(Format(ctsExpectedAMethodTypeButFound, [ + Result.Node.DescAsString])); + end; + finally + Params.Free; end; finally - Params.Free; + CLList.Free; end; finally DeactivateGlobalWriteLock; @@ -1124,9 +1130,9 @@ begin //debugln(['TEventsCodeTool.FindTypeOfPropertyInfo found: ',FindContextToString(AClassContext)]); // search property - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, AClassContext.Node); try - Params.Flags:=[fdfSearchInAncestors]; + Params.Flags:=[fdfSearchInAncestors,fdfSearchInHelpers]; if ExceptionOnNotFound then Include(Params.Flags,fdfExceptionOnNotFound); Params.ContextNode:=AClassContext.Node; Params.SetIdentifier(Self,PChar(PropName),nil); @@ -1240,7 +1246,7 @@ begin Params.Flags:=[fdfSearchInParentNodes, fdfIgnoreCurContextNode] +(fdfGlobals*Params.Flags) - -[fdfSearchInAncestors]; + -[fdfSearchInAncestors,fdfSearchInHelpers]; CurExprType:=GetExpressionTypeOfTypeIdentifier(Params); {$IFDEF VerboseTypeData} DebugLn('[TEventsCodeTool.CreateExprListFromMethodTypeData] B ', diff --git a/components/codetools/extractproctool.pas b/components/codetools/extractproctool.pas index 81e8ba63a0..0ab5a32a6e 100644 --- a/components/codetools/extractproctool.pas +++ b/components/codetools/extractproctool.pas @@ -1117,62 +1117,69 @@ var i: Integer; Cache: PWithVarCache; Params: TFindDeclarationParams; + CLList: THelpersList; begin Result:=false; - // check cache - if WithVarCache=nil then - WithVarCache:=TFPList.Create; - i:=WithVarCache.Count-1; - while (i>=0) and (PWithVarCache(WithVarCache[i])^.WithVarNode<>WithVarNode) do - dec(i); - if i>=0 then begin - Cache:=PWithVarCache(WithVarCache[i]); - end else begin - // resolve type of With variable - {$IFDEF CTDEBUG} - debugln(['IdentifierDefinedByWith NEW WithVar']); - {$ENDIF} - New(Cache); - WithVarCache.Add(Cache); - Cache^.WithVarNode:=WithVarNode; - Cache^.WithVarExpr:=CleanExpressionType; - Cache^.VarEndPos:=FindEndOfTerm(WithVarNode.StartPos,false,true); - Params:=TFindDeclarationParams.Create; - try - Params.ContextNode:=WithVarNode; - Params.Flags:=[fdfExceptionOnNotFound,fdfFunctionResult,fdfFindChildren]; - Cache^.WithVarExpr:=FindExpressionTypeOfTerm(WithVarNode.StartPos,-1,Params,true); - if (Cache^.WithVarExpr.Desc<>xtContext) - or (Cache^.WithVarExpr.Context.Node=nil) - or (not (Cache^.WithVarExpr.Context.Node.Desc - in (AllClasses+[ctnEnumerationType]))) - then begin - MoveCursorToCleanPos(Cache^.WithVarNode.StartPos); - RaiseException(ctsExprTypeMustBeClassOrRecord); - end; + CLList := THelpersList.Create; + try + FindHelpersInContext(WithVarNode, CLList); + // check cache + if WithVarCache=nil then + WithVarCache:=TFPList.Create; + i:=WithVarCache.Count-1; + while (i>=0) and (PWithVarCache(WithVarCache[i])^.WithVarNode<>WithVarNode) do + dec(i); + if i>=0 then begin + Cache:=PWithVarCache(WithVarCache[i]); + end else begin + // resolve type of With variable {$IFDEF CTDEBUG} - debugln(['IdentifierDefinedByWith WithVarExpr=',ExprTypeToString(Cache^.WithVarExpr)]); + debugln(['IdentifierDefinedByWith NEW WithVar']); + {$ENDIF} + New(Cache); + WithVarCache.Add(Cache); + Cache^.WithVarNode:=WithVarNode; + Cache^.WithVarExpr:=CleanExpressionType; + Cache^.VarEndPos:=FindEndOfTerm(WithVarNode.StartPos,false,true); + Params:=TFindDeclarationParams.Create(CLList); + try + Params.ContextNode:=WithVarNode; + Params.Flags:=[fdfExceptionOnNotFound,fdfFunctionResult,fdfFindChildren]; + Cache^.WithVarExpr:=FindExpressionTypeOfTerm(WithVarNode.StartPos,-1,Params,true); + if (Cache^.WithVarExpr.Desc<>xtContext) + or (Cache^.WithVarExpr.Context.Node=nil) + or (not (Cache^.WithVarExpr.Context.Node.Desc + in (AllClasses+[ctnEnumerationType]))) + then begin + MoveCursorToCleanPos(Cache^.WithVarNode.StartPos); + RaiseException(ctsExprTypeMustBeClassOrRecord); + end; + {$IFDEF CTDEBUG} + debugln(['IdentifierDefinedByWith WithVarExpr=',ExprTypeToString(Cache^.WithVarExpr)]); + {$ENDIF} + finally + Params.Free; + end; + end; + + if CleanPos<=Cache^.VarEndPos then exit; + + // search identifier in with var context + Params:=TFindDeclarationParams.Create(CLList); + try + Params.SetIdentifier(Self,@Src[CleanPos],nil); + Params.Flags:=[fdfSearchInAncestors,fdfSearchInHelpers]; + Params.ContextNode:=Cache^.WithVarExpr.Context.Node; + Result:=Cache^.WithVarExpr.Context.Tool.FindIdentifierInContext(Params); + {$IFDEF CTDEBUG} + debugln(['IdentifierDefinedByWith Identifier=',GetIdentifier(@Src[CleanPos]),' FoundInWith=',Result,' WithVar="',dbgstr(Src,WithVarNode.StartPos,10),'"']); {$ENDIF} finally Params.Free; end; - end; - - if CleanPos<=Cache^.VarEndPos then exit; - - // search identifier in with var context - Params:=TFindDeclarationParams.Create; - try - Params.SetIdentifier(Self,@Src[CleanPos],nil); - Params.Flags:=[fdfSearchInAncestors]; - Params.ContextNode:=Cache^.WithVarExpr.Context.Node; - Result:=Cache^.WithVarExpr.Context.Tool.FindIdentifierInContext(Params); - {$IFDEF CTDEBUG} - debugln(['IdentifierDefinedByWith Identifier=',GetIdentifier(@Src[CleanPos]),' FoundInWith=',Result,' WithVar="',dbgstr(Src,WithVarNode.StartPos,10),'"']); - {$ENDIF} finally - Params.Free; + CLList.Free; end; end; @@ -1765,12 +1772,13 @@ var IsInSelection:=(VarStartPos>=BlockStartPos) and (VarStartPos=BlockEndPos); MoveCursorToCleanPos(VarStartPos); - Params:=TFindDeclarationParams.Create; + VarNode:=FindDeepestNodeAtPos(VarStartPos,true); + Params:=TFindDeclarationParams.Create(Self, VarNode); try // find declaration - Params.ContextNode:=FindDeepestNodeAtPos(VarStartPos,true); + Params.ContextNode:=VarNode; Params.Flags:=[fdfSearchInParentNodes,fdfExceptionOnNotFound, - fdfTopLvlResolving,fdfSearchInAncestors]; + fdfTopLvlResolving,fdfSearchInAncestors,fdfSearchInHelpers]; Params.SetIdentifier(Self,@Src[VarStartPos],@CheckSrcIdentifier); {$IFDEF CTDebug} DebugLn('AddVariableAtCursor Searching ',GetIdentifier(Params.Identifier)); diff --git a/components/codetools/finddeclarationtool.pas b/components/codetools/finddeclarationtool.pas index 5598724348..f5f7c0c864 100644 --- a/components/codetools/finddeclarationtool.pas +++ b/components/codetools/finddeclarationtool.pas @@ -169,7 +169,11 @@ type // top lvl variable. Calling DoOnIdentifierFound. fdfDoNotCache, // result will not be cached fdfExtractOperand, // operand will be extracted - fdfPropertyResolving // used with fdfExtractOperand to resolve properties to getters + fdfPropertyResolving, // used with fdfExtractOperand to resolve properties to getters + + fdfSearchInHelpers, // search in class/record/type helpers too + fdfSearchInHelpersInTheEnd, // search in helpers after current class (used with inherited call in helper) + fdfTypeType // do not resolve TMyString = type string; ); TFindDeclarationFlags = set of TFindDeclarationFlag; @@ -179,9 +183,9 @@ const fdfExtractOperand, fdfPropertyResolving]; fdfGlobalsSameIdent = fdfGlobals+[fdfExceptionOnPredefinedIdent, fdfIgnoreMissingParams, fdfIgnoreUsedUnits, fdfDoNotCache, - fdfOnlyCompatibleProc, fdfSearchInAncestors, fdfCollect]; + fdfOnlyCompatibleProc, fdfSearchInAncestors, fdfCollect, fdfSearchInHelpers]; // initial flags for searches - fdfDefaultForExpressions = [fdfSearchInParentNodes, fdfSearchInAncestors, + fdfDefaultForExpressions = [fdfSearchInParentNodes, fdfSearchInAncestors, fdfSearchInHelpers, fdfExceptionOnNotFound,fdfIgnoreCurContextNode]; type @@ -304,6 +308,8 @@ const xtAllTypes = [Low(TExpressionTypeDesc)..High(TExpressionTypeDesc)]-[xtNone]; xtAllPredefinedTypes = xtAllTypes-[xtContext]; + xtAllIdentTypes = xtAllTypes - [xtConstOrdInteger,xtConstBoolean,xtConstReal,xtConstString,xtConstSet,xtCompilerFunc,xtNil]; + xtAllIdentPredefinedTypes = xtAllIdentTypes - [xtContext]; xtAllIntegerTypes = [xtInt64, xtQWord, xtConstOrdInteger, xtLongint, xtLongWord, xtWord, xtCardinal, xtSmallInt, xtShortInt, xtByte]; @@ -451,11 +457,15 @@ type FoundProc. } + THelpersList = class; + TFindDeclarationParams = class(TObject) private FFoundProcStackFirst: PFoundProc;//list of all saved PFoundProc FFoundProcStackLast: PFoundProc; FExtractedOperand: string; + FHelpers: THelpersList; + FFreeHelpers: Boolean; procedure ClearFoundProc; procedure FreeFoundProc(aFoundProc: PFoundProc; FreeNext: boolean); procedure RemoveFoundProcFromList(aFoundProc: PFoundProc); @@ -494,7 +504,8 @@ type NewPos: TCodeXYPosition; NewTopLine: integer; NewFlags: TFoundDeclarationFlags; - constructor Create; + constructor Create(AHelpers: THelpersList = nil); + constructor Create(Tool: TFindDeclarationTool; AContextNode: TCodeTreeNode); destructor Destroy; override; procedure Clear; procedure Save(out Input: TFindDeclarationInput); @@ -508,6 +519,7 @@ type procedure SetIdentifier(NewIdentifierTool: TFindDeclarationTool; NewIdentifier: PChar; NewOnIdentifierFound: TOnIdentifierFound); procedure WriteDebugReport; + property Helpers: THelpersList read FHelpers; end; @@ -549,6 +561,32 @@ type ECodeToolUnitNotFound = class(ECodeToolFileNotFound) end; + THelpersListItem = class(TObject) + ForExprType: TExpressionType; + HelperContext: TFindContext; + function CalcMemSize: PtrUInt; + end; + THelpersListRec = record + ForExprType: TExpressionType; + HelperContext: TFindContext; + end; + THelpersList = class + private + FTree: TAVLTree; + public + function AddFromHelperNode(HelperNode: TCodeTreeNode; + Tool: TFindDeclarationTool; RewriteOld: Boolean): THelpersListItem; + procedure AddFromList(const ExtList: THelpersList); + function FindFromClassNode(ClassNode: TCodeTreeNode; Tool: TFindDeclarationTool): TFindContext; + function FindFromExprType(const ExprType: TExpressionType): TFindContext; + procedure DeleteHelperNode(HelperNode: TCodeTreeNode; Tool: TFindDeclarationTool); + constructor Create; + destructor Destroy; override; + procedure Clear; + function Count: Integer; + function CalcMemSize: PtrUInt; + end; + //---------------------------------------------------------------------------- { TFindDeclarationTool } @@ -558,6 +596,7 @@ type FAdjustTopLineDueToComment: boolean; FDirectoryCache: TCTDirectoryCache; FInterfaceIdentifierCache: TInterfaceIdentifierCache; + FInterfaceHelperCache: THelpersList; FOnFindUsedUnit: TOnFindUsedUnit; FOnGetCodeToolForBuffer: TOnGetCodeToolForBuffer; FOnGetDirectoryCache: TOnGetDirectoryCache; @@ -597,6 +636,8 @@ type Params: TFindDeclarationParams): boolean; function FindIdentifierInWithVarContext(WithVarNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean; + function FindIdentifierInAncestors(ClassNode: TCodeTreeNode; + Params: TFindDeclarationParams; var IdentFoundResult: TIdentifierFoundResult): boolean; function FindIdentifierInAncestors(ClassNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean; function FindIdentifierInUsesSection(UsesNode: TCodeTreeNode; @@ -657,7 +698,7 @@ type out ExprType: TExpressionType): string; function FindEnumeratorOfClass(ClassNode: TCodeTreeNode; ExceptionOnNotFound: boolean; out ExprType: TExpressionType; - AliasType: PFindContext = nil): boolean; + AliasType: PFindContext = nil; Helpers: THelpersList = nil): boolean; function FindOperatorEnumerator(Node: TCodeTreeNode; ExprType: TExpressionType; Need: TFindOperatorEnumerator; out ResultExprType: TExpressionType): boolean; @@ -681,6 +722,8 @@ type protected function CheckSrcIdentifier(Params: TFindDeclarationParams; const FoundContext: TFindContext): TIdentifierFoundResult; + function FindDeclarationOfIdentAtParam( + Params: TFindDeclarationParams; out ExprType: TExpressionType): boolean; function FindDeclarationOfIdentAtParam( Params: TFindDeclarationParams): boolean; function IdentifierIsDefined(const IdentAtom: TAtomPosition; @@ -694,8 +737,6 @@ type out IsForward: boolean): boolean; function FindNonForwardClass(ForwardNode: TCodeTreeNode): TCodeTreeNode; function FindNonForwardClass(Params: TFindDeclarationParams): boolean; - function FindCodeToolForUsedUnit(const AnUnitName, AnUnitInFilename: string; - ExceptionOnNotFound: boolean): TFindDeclarationTool; function FindIdentifierInInterface(AskingTool: TFindDeclarationTool; Params: TFindDeclarationParams): boolean; function CompareNodeIdentifier(Node: TCodeTreeNode; @@ -751,6 +792,10 @@ type SearchSmartFlags: TFindSmartFlags; out NewTool: TFindDeclarationTool; out NewNode: TCodeTreeNode; out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean; + function FindDeclaration(const CursorPos: TCodeXYPosition; + SearchSmartFlags: TFindSmartFlags; + out NewExprType: TExpressionType; + out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean; function FindDeclarationInInterface(const Identifier: string; out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean; function FindDeclarationWithMainUsesSection(const Identifier: string; @@ -781,6 +826,8 @@ type function GetUnitForUsesSection(TargetTool: TFindDeclarationTool): string; deprecated; function IsHiddenUsedUnit(TheUnitName: PChar): boolean; + function FindCodeToolForUsedUnit(const AnUnitName, AnUnitInFilename: string; + ExceptionOnNotFound: boolean): TFindDeclarationTool; function FindUnitSource(const AnUnitName, AnUnitInFilename: string; ExceptionOnNotFound: boolean; ErrorPos: integer = 0): TCodeBuffer; @@ -827,6 +874,8 @@ type Params: TFindDeclarationParams; FindClassContext: boolean; ExceptionOnNotFound: boolean = true): boolean; // with interfaces + function FindExtendedExprOfHelper(HelperNode: TCodeTreeNode): TExpressionType; + function FindReferences(const CursorPos: TCodeXYPosition; SkipComments: boolean; out ListOfPCodeXYPosition: TFPList): boolean; function FindUnitReferences(UnitCode: TCodeBuffer; @@ -841,7 +890,19 @@ type function CleanPosIsDeclarationIdentifier(CleanPos: integer; Node: TCodeTreeNode): boolean; + procedure FindHelpersInContext(StartNode: TCodeTreeNode; Helpers: THelpersList); + procedure FindHelpersInContext(Params: TFindDeclarationParams); + procedure FindHelpersInUsesSection(UsesNode: TCodeTreeNode; + Helpers: THelpersList); + procedure FindHelpersInInterface(AskingTool: TFindDeclarationTool; + Helpers: THelpersList); + function FindIdentifierInContext(Params: TFindDeclarationParams; + var IdentFoundResult: TIdentifierFoundResult): boolean; function FindIdentifierInContext(Params: TFindDeclarationParams): boolean; + function FindIdentifierInBasicTypeHelpers(ExprType: TExpressionTypeDesc; + Params: TFindDeclarationParams): Boolean; + function FindIdentifierInBasicTypeHelpers(ExprType: TExpressionTypeDesc; + Params: TFindDeclarationParams; out FoundInTool: TFindDeclarationTool): Boolean; function FindNthParameterNode(Node: TCodeTreeNode; ParameterIndex: integer): TCodeTreeNode; function GetFirstParameterNode(Node: TCodeTreeNode): TCodeTreeNode; @@ -922,6 +983,7 @@ type TargetUnitName: string; ListOfPCodeXYPosition: TFPList; Params: TFindDeclarationParams; + constructor Create(Tool: TFindDeclarationTool; AContextNode: TCodeTreeNode); destructor Destroy; override; end; @@ -1230,6 +1292,168 @@ begin ListOfPFindContext:=nil; end; +{ THelpersListItem } + +function THelpersListItem.CalcMemSize: PtrUInt; +begin + Result := InstanceSize; +end; + +{ THelpersList } + +function CompareHelpersList(Item1, Item2: Pointer): Integer; +var + I1, I2: THelpersListItem; +begin + I1 := THelpersListItem(Item1); + I2 := THelpersListItem(Item2); + Result := Ord(I1.ForExprType.Desc) - Ord(I2.ForExprType.Desc); + if Result = 0 then + Result := ComparePointers(I1.ForExprType.Context.Tool, I2.ForExprType.Context.Tool); + if Result = 0 then + Result := ComparePointers(I1.ForExprType.Context.Node, I2.ForExprType.Context.Node); +end; + +function CompareHelpersListExprType(Item1, Item2: Pointer): Integer; +var + I1: PExpressionType; + I2: THelpersListItem; +begin + I1 := PExpressionType(Item1); + I2 := THelpersListItem(Item2); + Result := Ord(I1^.Desc) - Ord(I2.ForExprType.Desc); + if Result = 0 then + Result := ComparePointers(I1^.Context.Tool, I2.ForExprType.Context.Tool); + if Result = 0 then + Result := ComparePointers(I1^.Context.Node, I2.ForExprType.Context.Node); +end; + +procedure THelpersList.AddFromList(const ExtList: THelpersList); + function CopyNode(ANode: TAVLTreeNode): THelpersListItem; + var + FromNode: THelpersListItem; + begin + FromNode := THelpersListItem(ANode.Data); + if Self.FTree.FindKey(FromNode, @CompareHelpersList) <> nil then + Exit;//FPC & Delphi don't support duplicate class helpers! + Result := THelpersListItem.Create; + Result.HelperContext := FromNode.HelperContext; + Result.ForExprType := FromNode.ForExprType; + Self.FTree.Add(Result); + end; +var + Node: TAVLTreeNode; +begin + for Node in ExtList.FTree do + CopyNode(Node); +end; + +function THelpersList.CalcMemSize: PtrUInt; +var + Node: TAVLTreeNode; +begin + Result:=PtrUInt(InstanceSize)+PtrUInt(FTree.InstanceSize); + for Node in FTree do + Inc(Result, THelpersListItem(Node.Data).CalcMemSize); +end; + +function THelpersList.AddFromHelperNode(HelperNode: TCodeTreeNode; + Tool: TFindDeclarationTool; RewriteOld: Boolean): THelpersListItem; +var + OldKey: TAVLTreeNode; + ExprType: TExpressionType; +begin + ExprType:=Tool.FindExtendedExprOfHelper(HelperNode); + + if ExprType.Desc in xtAllIdentTypes then + begin + OldKey := FTree.FindKey(@ExprType, @CompareHelpersListExprType); + if OldKey <> nil then + begin//FPC & Delphi don't support duplicate class helpers! + if RewriteOld then + FTree.FreeAndDelete(OldKey) + else + Exit(THelpersListItem(OldKey.Data)); + end; + + Result := THelpersListItem.Create; + Result.ForExprType := ExprType; + Result.HelperContext.Node := HelperNode; + Result.HelperContext.Tool := Tool; + FTree.Add(Result); + end else + Result := nil; +end; + +procedure THelpersList.Clear; +begin + FTree.FreeAndClear; +end; + +function THelpersList.Count: Integer; +begin + Result := FTree.Count; +end; + +constructor THelpersList.Create; +begin + inherited Create; + + FTree := TAVLTree.Create(@CompareHelpersList); +end; + +procedure THelpersList.DeleteHelperNode(HelperNode: TCodeTreeNode; + Tool: TFindDeclarationTool); +var + OldKey: TAVLTreeNode; + ExprType: TExpressionType; +begin + ExprType:=Tool.FindExtendedExprOfHelper(HelperNode); + + if ExprType.Desc in xtAllIdentTypes then + begin + OldKey := FTree.FindKey(@ExprType, @CompareHelpersListExprType); + if OldKey <> nil then + FTree.FreeAndDelete(OldKey); + end; +end; + +destructor THelpersList.Destroy; +begin + Clear; + FTree.Free; + inherited Destroy; +end; + +function THelpersList.FindFromClassNode(ClassNode: TCodeTreeNode; + Tool: TFindDeclarationTool): TFindContext; +var + ExprType: TExpressionType; +begin + ExprType.Desc:=xtContext; + ExprType.Context.Node:=ClassNode; + ExprType.Context.Tool:=Tool; + Result := FindFromExprType(ExprType); +end; + +function THelpersList.FindFromExprType(const ExprType: TExpressionType + ): TFindContext; +var + Item: TAVLTreeNode; +begin + Item := FTree.FindKey(@ExprType, @CompareHelpersListExprType); + if Assigned(Item) then + Result := THelpersListItem(Item.Data).HelperContext + else + Result := CleanFindContext; +end; + +constructor TFindUsedUnitReferences.Create(Tool: TFindDeclarationTool; AContextNode: TCodeTreeNode); +begin + inherited Create; + Params:=TFindDeclarationParams.Create(Tool, AContextNode); +end; + destructor TFindUsedUnitReferences.Destroy; begin FreeAndNil(Params); @@ -1283,12 +1507,12 @@ begin // find CodeTreeNode at cursor CursorNode:=BuildSubTreeAndFindDeepestNodeAtPos(CleanCursorPos,true); // search - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); Params.ContextNode:=CursorNode; Params.SetIdentifier(Self,Identifier,nil); Params.Flags:=[fdfSearchInParentNodes,fdfExceptionOnNotFound, fdfExceptionOnPredefinedIdent, - fdfTopLvlResolving,fdfSearchInAncestors, + fdfTopLvlResolving,fdfSearchInAncestors,fdfSearchInHelpers, fdfIgnoreCurContextNode]; FindIdentifierInContext(Params); // convert result to nice source position @@ -1304,9 +1528,8 @@ begin end; function TFindDeclarationTool.FindDeclaration(const CursorPos: TCodeXYPosition; - SearchSmartFlags: TFindSmartFlags; - out NewTool: TFindDeclarationTool; out NewNode: TCodeTreeNode; - out NewPos: TCodeXYPosition; out NewTopLine: integer): boolean; + SearchSmartFlags: TFindSmartFlags; out NewExprType: TExpressionType; out + NewPos: TCodeXYPosition; out NewTopLine: integer): boolean; var CleanCursorPos: integer; CursorNode, ClassNode: TCodeTreeNode; @@ -1412,18 +1635,18 @@ var NamePos: TAtomPosition; begin Result:=false; - NewTool:=nil; - NewNode:=nil; + NewExprType :=CleanExpressionType; if Assigned(FOnGetCodeToolForBuffer) then - NewTool:=FOnGetCodeToolForBuffer(Self,ACode,false); - if NewTool=nil then exit; - NewTool.BuildTree(lsrSourceName); - if not NewTool.GetSourceNamePos(NamePos) then exit; - NewNode:=NewTool.Tree.Root; - if not NewTool.JumpToCleanPos(NamePos.StartPos,NamePos.StartPos, + NewExprType.Context.Tool:=FOnGetCodeToolForBuffer(Self,ACode,false); + if NewExprType.Context.Tool=nil then exit; + NewExprType.Context.Tool.BuildTree(lsrSourceName); + if not NewExprType.Context.Tool.GetSourceNamePos(NamePos) then exit; + NewExprType.Context.Node:=NewExprType.Context.Tool.Tree.Root; + if not NewExprType.Context.Tool.JumpToCleanPos(NamePos.StartPos,NamePos.StartPos, NamePos.StartPos,NewPos,NewTopLine,false) then exit; Result:=true; + NewExprType.Desc:=xtContext; end; {$IFDEF VerboseFindDeclarationFail} @@ -1488,8 +1711,9 @@ var LineRange: TLineRange; begin Result:=false; - NewTool:=nil; - NewNode:=nil; + NewExprType:=CleanExpressionType; + NewPos.X:=-1; + NewPos.Y:=-1; SkipChecks:=false; // check cursor in source if (CursorPos.Y<1) or (CursorPos.Y>CursorPos.Code.LineCount) @@ -1530,28 +1754,29 @@ begin and CleanPosIsDeclarationIdentifier(CleanCursorPos,CursorNode) then begin //DebugLn(['TFindDeclarationTool.FindDeclaration CleanPosIsDeclarationIdentifier']); - NewTool:=Self; - NewNode:=CursorNode; + NewExprType.Desc:=xtContext; + NewExprType.Context.Tool:=Self; + NewExprType.Context.Node:=CursorNode; CleanCursorPos:=GetIdentStartPosition(Src,CleanCursorPos); if CursorNode.Desc=ctnVarDefinition then begin // if this is a parameter, try to find the corresponding declaration - NewNode:=FindCorrespondingProcParamNode(NewNode); - if (NewNode<>nil) and (NewNode.StartPosnil) and (NewExprType.Context.Node.StartPosnil) and (NewNode.Desc=ctnProcedure) then - NewNode:=NewNode.FirstChild; - if (NewNode<>nil) and (NewNode.StartPosnil) and (NewExprType.Context.Node.Desc=ctnProcedure) then + NewExprType.Context.Node:=NewExprType.Context.Node.FirstChild; + if (NewExprType.Context.Node<>nil) and (NewExprType.Context.Node.StartPos= 0) and (NewPos.Y >= 0); + if Result then begin + NewTool := ExprType.Context.Tool; + NewNode := ExprType.Context.Node; + end else begin + NewTool := nil; + NewNode := nil; + end; +end; + function TFindDeclarationTool.FindDeclarationInInterface( const Identifier: string; out NewPos: TCodeXYPosition; out NewTopLine: integer ): boolean; @@ -1722,7 +1971,7 @@ begin UsesNode:=FindMainUsesNode; if UsesNode=nil then exit; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, FindLastNode); ActivateGlobalWriteLock; try Params.Flags:=[fdfExceptionOnNotFound]; @@ -1773,7 +2022,7 @@ begin //DebugLn('TFindDeclarationTool.FindDeclarationOfPropertyPath ',MainFilename,' PropertyPath="',PropertyPath,'"'); if PropertyPath='' then exit; ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, FindLastNode); try BuildTree(lsrInitializationStart); @@ -1843,7 +2092,7 @@ begin exit; end; //DebugLn('TFindDeclarationTool.FindDeclarationOfPropertyPath Identifier="',identifier,'"'); - Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors]; + Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors,fdfSearchInHelpers]; Params.SetIdentifier(Self,PChar(Pointer(Identifier)),nil); Params.ContextNode:=Context.Node; if IsLastProperty then @@ -1867,7 +2116,7 @@ begin Params.ContextNode:=Context.Tool.FindClassOrInterfaceNode(Context.Node); if Params.ContextNode=nil then Params.ContextNode:=Context.Node; - Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors, + Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors,fdfSearchInHelpers, fdfFindVariable,fdfIgnoreCurContextNode]; //DebugLn(['TFindDeclarationTool.FindDeclarationOfPropertyPath ',Context.Tool.MainFilename,' ',Params.ContextNode.DescAsString,' ',Context.Tool.CleanPosToStr(Params.ContextNode.StartPos)]); if not Context.Tool.FindIdentifierInContext(Params) then exit; @@ -2355,6 +2604,8 @@ var NodeStr: String; Params: TFindDeclarationParams; Tool: TFindDeclarationTool; + HelperForNode: TCodeTreeNode; + SubNode: TCodeTreeNode; begin Result:=''; @@ -2432,15 +2683,47 @@ begin Result += ExtractNode(TypeNode, [phpCommentsToSpace]); end; ctnClass, ctnClassInterface, ctnDispinterface, - ctnObject, ctnRecordType, ctnRangedArrayType, ctnOpenArrayType, + ctnClassHelper, ctnTypeHelper, ctnRecordHelper, + ctnObject, ctnRangedArrayType, ctnOpenArrayType, ctnObjCClass, ctnObjCCategory, ctnObjCProtocol, ctnCPPClass: begin MoveCursorToNodeStart(TypeNode); - ReadNextAtom; - Result+=GetAtom; - if (TypeNode.FirstChild<>nil) - and (TypeNode.FirstChild.Desc = ctnClassInheritance) then - Result += ExtractNode(TypeNode.FirstChild, []); + case TypeNode.Desc of + ctnClass: Result:=Result+'class'; + ctnClassHelper: Result:=Result+'class helper'; + ctnRecordHelper: Result:=Result+'record helper'; + ctnTypeHelper: Result:=Result+'type helper'; + ctnObject: Result:=Result+'object'; + ctnObjCClass: Result:=Result+'objcclass'; + ctnObjCCategory: Result:=Result+'objccategory'; + ctnCPPClass: Result:=Result+'cppclass'; + ctnClassInterface: Result:=Result+'interface'; + ctnObjCProtocol: Result:=Result+'objcprotocol'; + ctnDispinterface: Result:=Result+'dispinterface'; + ctnRangedArrayType, ctnOpenArrayType: Result:=Result+'array'; + end; + try + BuildSubTree(TypeNode); + except + on ECodeToolError do ; + end; + if TypeNode.Desc in [ctnClassHelper, ctnRecordHelper, ctnTypeHelper] then + HelperForNode := FindHelperForNode(TypeNode) + else + HelperForNode := nil; + SubNode:=FindInheritanceNode(TypeNode); + if SubNode<>nil then + Result:=Result+ExtractNode(SubNode,[]); + if HelperForNode<>nil then + Result:=Result+' '+ExtractNode(HelperForNode,[]); + end; + ctnRecordType: + Result:=Result+'record'; + ctnTypeType: + begin + Result:=Result+'type'; + if TypeNode.FirstChild <> nil then + Result:=Result+' '+ExtractNode(TypeNode.FirstChild,[]); end; ctnConstant: begin @@ -2502,10 +2785,10 @@ begin // property without type // -> search ancestor property if not Tool.MoveCursorToPropName(Node) then break; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, Node); try Params.SetIdentifier(Tool,@Tool.Src[Tool.CurPos.StartPos],nil); - Params.Flags:=[fdfSearchInAncestors]; + Params.Flags:=[fdfSearchInAncestors,fdfSearchInHelpers]; if not FindIdentifierInAncestors(Node.Parent.Parent,Params) then break; Tool:=Params.NewCodeTool; Node:=Params.NewNode; @@ -2576,7 +2859,7 @@ begin Result:=false; if (ANode=nil) then exit; ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, ANode); try Params.Flags:=Params.Flags+[fdfFunctionResult,fdfFindChildren]; FindContext:=FindBaseTypeOfNode(Params,ANode); @@ -2615,13 +2898,21 @@ end; function TFindDeclarationTool.FindDeclarationOfIdentAtParam( Params: TFindDeclarationParams): boolean; +var + ExprType: TExpressionType; +begin + Result := FindDeclarationOfIdentAtParam(Params, ExprType) and (Params.NewNode<>nil); +end; + +function TFindDeclarationTool.FindDeclarationOfIdentAtParam( + Params: TFindDeclarationParams; out ExprType: TExpressionType): boolean; { searches an identifier in clean code, parses code in front and after the identifier Params: Identifier in clean source ContextNode // = DeepestNode at Cursor - + Result: true, if found @@ -2631,7 +2922,6 @@ function TFindDeclarationTool.FindDeclarationOfIdentAtParam( } var StartPos, EndPos: integer; - ExprType: TExpressionType; SkipForward: boolean; begin {$IFDEF CTDEBUG} @@ -2673,7 +2963,7 @@ begin else DebugLn('NOT FOUND'); {$ENDIF} - Result:=Params.NewNode<>nil; + Result:=ExprType.Desc<>xtNone; end; function TFindDeclarationTool.IdentifierIsDefined(const IdentAtom: TAtomPosition; @@ -2705,14 +2995,15 @@ begin end; Params.ContextNode:=ContextNode; Params.SetIdentifier(Self,Identifier,nil); - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfTopLvlResolving,fdfFindVariable,fdfIgnoreCurContextNode]; Result:=FindIdentifierInContext(Params); //DebugLn(['TFindDeclarationTool.IdentifierIsDefined END Result=',Result]); end; function TFindDeclarationTool.FindIdentifierInContext( - Params: TFindDeclarationParams): boolean; + Params: TFindDeclarationParams; var IdentFoundResult: TIdentifierFoundResult + ): boolean; { searches an identifier in context node It does not care about code in front of the identifier like 'a.Identifer'. @@ -2733,6 +3024,8 @@ var SearchRangeFlags: TNodeCacheEntryFlags; NodeCacheEntryFlags: TNodeCacheEntryFlags; Flags: TFindDeclarationFlags; + OldFlags: TFindDeclarationFlags; + SearchInHelpersInTheEnd: Boolean; procedure InitNodesAndCacheAccess; @@ -2866,8 +3159,7 @@ var Params.IdentifierTool.RaiseExceptionFmt(ctsIdentifierNotFound, [Identifier]); end; - - var IdentFoundResult: TIdentifierFoundResult; + begin Result:=true; FindIdentifierInContext:=NewResult and (not (fdfCollect in Flags)); @@ -3206,12 +3498,42 @@ var end; end; + function SearchInHelpers: Boolean; + var + CHContext: TFindContext; + begin + Result := False; + SearchInHelpersInTheEnd := False; + CHContext := Params.Helpers.FindFromClassNode(StartContextNode, Self); + + if Assigned(CHContext.Tool) and Assigned(CHContext.Node) then + begin + OldFlags := Params.Flags; + try + Exclude(Params.Flags, fdfExceptionOnNotFound); + Exclude(Params.Flags, fdfIgnoreCurContextNode); + Exclude(Params.Flags, fdfSearchInHelpers); + Include(Params.Flags, fdfIgnoreUsedUnits); + Params.ContextNode := CHContext.Node; + + if CHContext.Tool.FindIdentifierInContext(Params, IdentFoundResult) then + begin + if (IdentFoundResult = ifrAbortSearch) or ( + (IdentFoundResult = ifrSuccess) and + CheckResult(IdentFoundResult=ifrSuccess,False)) + then + Result := True; + end; + finally + Params.Flags := OldFlags; + end; + end; + end; + function SearchNextNode: boolean; const AbortNoCacheResult = false; Proceed = true; - var - OldInput: TFindDeclarationInput; begin repeat // search for prior node @@ -3233,15 +3555,31 @@ var end; end; - if (ContextNode.Desc in (AllClasses-[ctnRecordType])) then begin + if (ContextNode.Desc in (AllClasses)) then begin//allow ctnRecordType and ctnTypeTypeBeforeHelper: they can have helpers! if (fdfSearchInAncestors in Flags) then begin // after searching in a class definition, search in its ancestors - // ToDo: check for cycles in ancestors - Params.Save(OldInput); + + OldFlags := Params.Flags; Exclude(Params.Flags,fdfExceptionOnNotFound); - Result:=FindIdentifierInAncestors(ContextNode,Params); - Params.Load(OldInput,true); + Exclude(Params.Flags,fdfSearchInHelpersInTheEnd); + + //leaving current class -> check if search in helpers in the end + if SearchInHelpersInTheEnd then + begin + Result := SearchInHelpers; + Params.Flags := OldFlags; + if Result then + begin + Result := True; + FindIdentifierInContext:=true; + Exit(AbortNoCacheResult); + end; + end; + + Exclude(Params.Flags,fdfExceptionOnNotFound); + Result:=FindIdentifierInAncestors(ContextNode,Params,IdentFoundResult); + Params.Flags := OldFlags; if Result then begin FindIdentifierInContext:=true; {$IFDEF ShowCollect} @@ -3338,7 +3676,7 @@ var ctnClassClassVar, ctnRecordVariant, ctnProcedureHead, ctnParameterList, - ctnClassInheritance: + ctnClassInheritance,ctnHelperFor: // these codetreenodes build a parent-child-relationship, but // for pascal it is only a range, hence after searching in the // children of the last node, search must continue in the children @@ -3348,6 +3686,7 @@ var ctnClass, ctnClassInterface, ctnDispinterface, ctnObject, ctnObjCClass, ctnObjCCategory, ctnObjCProtocol, ctnCPPClass, ctnRecordType, ctnRecordCase, + ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnEnumerationType: // do not search again in this node, go on ... ; @@ -3420,6 +3759,20 @@ begin exit; end; + //find class helper functions + SearchInHelpersInTheEnd := False; + if (fdfSearchInHelpers in Flags) and + (ContextNode.Desc in [ctnClass, ctnRecordType, ctnTypeType]) and + Assigned(ContextNode.Parent) and (ContextNode.Parent.Desc = ctnTypeDefinition) + then + begin + if (fdfSearchInHelpersInTheEnd in Flags) then + SearchInHelpersInTheEnd := True + else begin + if SearchInHelpers then Exit; + end; + end; + //try // search in the Tree of this tool repeat @@ -3462,6 +3815,7 @@ begin ctnClass, ctnClassInterface, ctnDispinterface, ctnObject, ctnObjCClass, ctnObjCCategory, ctnObjCProtocol, ctnCPPClass, ctnRecordType, ctnRecordVariant, + ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnEnumerationType, ctnParameterList: // these nodes build a parent-child relationship. But in pascal @@ -3554,6 +3908,12 @@ begin if not SearchNextNode then exit; end; until ContextNode=nil; + + if SearchInHelpersInTheEnd then + begin + if SearchInHelpers then Exit; + end; + if LastSearchedNode=Tree.Root then begin if SearchDefault then exit; end; @@ -3722,7 +4082,7 @@ var NewCode: TCodeBuffer; begin IsPredefined:=false; - SubParams:=TFindDeclarationParams.Create; + SubParams:=TFindDeclarationParams.Create(Params.Helpers); try SubParams.GenParams := Params.GenParams; IdentStart:=CleanPos; @@ -4067,7 +4427,7 @@ begin if not MoveCursorToPropName(Result.Node) then break; OldPos:=CurPos.StartPos; Params.SetIdentifier(Self,@Src[CurPos.StartPos],nil); - Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors] + Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors,fdfSearchInHelpers] +(fdfGlobalsSameIdent*Params.Flags); FindIdentifierInAncestors(Result.Node.Parent.Parent,Params); TestContext.Tool:=Params.NewCodeTool; @@ -4088,6 +4448,8 @@ begin break; end else if (Result.Node.Desc=ctnTypeType) then begin + if fdfTypeType in Params.Flags then + break; // the type node is wanted, not its real type // a TypeType is for example 'MyInt = type integer;' // the context is not the 'type' keyword, but the identifier after it. Result.Node:=Result.Node.FirstChild; @@ -4137,6 +4499,45 @@ begin {$ENDIF} end; +function TFindDeclarationTool.FindIdentifierInBasicTypeHelpers( + ExprType: TExpressionTypeDesc; Params: TFindDeclarationParams): Boolean; +var + FoundTool: TFindDeclarationTool; +begin + Result := FindIdentifierInBasicTypeHelpers(ExprType, Params, FoundTool{%H-}); +end; + +function TFindDeclarationTool.FindIdentifierInBasicTypeHelpers( + ExprType: TExpressionTypeDesc; Params: TFindDeclarationParams; out + FoundInTool: TFindDeclarationTool): Boolean; +var + OldFlags: TFindDeclarationFlags; + FullExprType: TExpressionType; + CHContext: TFindContext; +begin + FullExprType := CleanExpressionType; + FullExprType.Desc := ExprType; + //find class helper functions + CHContext := Params.Helpers.FindFromExprType(FullExprType); + + if Assigned(CHContext.Node) and Assigned(CHContext.Tool) then + begin + OldFlags := Params.Flags; + try + Exclude(Params.Flags, fdfExceptionOnNotFound); + Exclude(Params.Flags, fdfIgnoreCurContextNode); + Include(Params.Flags, fdfIgnoreUsedUnits); + Params.ContextNode := CHContext.Node; + + FoundInTool := CHContext.Tool; + Result := FoundInTool.FindIdentifierInContext(Params); + finally + Params.Flags := OldFlags; + end; + end else + Result := False; +end; + function TFindDeclarationTool.FindDeclarationAndOverload( const CursorPos: TCodeXYPosition; out ListOfPCodeXYPosition: TFPList; Flags: TFindDeclarationListFlags): boolean; @@ -4302,10 +4703,10 @@ begin // for example A.Identifier IsSubIdentifier:=true; // search the context of A and add it to the ListOfPFindContext - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); try Params.ContextNode:=CursorNode; - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfTopLvlResolving,fdfFunctionResult]; ExprType:=FindExpressionTypeOfTerm(-1,CleanPos,Params,false); finally @@ -4326,10 +4727,10 @@ begin WithNode:=Node.Parent; while WithNode<>nil do begin if WithNode.Desc<>ctnWithVariable then break; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, WithNode); try Params.ContextNode:=WithNode; - Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors, + Params.Flags:=[fdfExceptionOnNotFound,fdfSearchInAncestors,fdfSearchInHelpers, fdfSearchInParentNodes,fdfFunctionResult,fdfIgnoreCurContextNode, fdfFindChildren]; ExprType:=FindExpressionResultType(Params,WithNode.StartPos,-1); @@ -4369,6 +4770,14 @@ begin Result:=true; end; +function TFindDeclarationTool.FindIdentifierInAncestors( + ClassNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean; +var + IdentFoundResult: TIdentifierFoundResult; +begin + Result := FindIdentifierInAncestors(ClassNode, Params, IdentFoundResult{%H-}); +end; + function TFindDeclarationTool.FindClassAndAncestors(ClassNode: TCodeTreeNode; out ListOfPFindContext: TFPList; ExceptionOnNotFound: boolean): boolean; var @@ -4427,6 +4836,78 @@ begin end; end; +procedure TFindDeclarationTool.FindHelpersInContext( + StartNode: TCodeTreeNode; Helpers: THelpersList); + + function SearchNextNode: TCodeTreeNode; + begin + Result := StartNode.PriorBrother; + if Assigned(Result) then + begin + while Assigned(Result.LastChild) do + Result := Result.LastChild; + end else + Result := StartNode.Parent; + end; +begin + while Assigned(StartNode) do + begin + case StartNode.Desc of + ctnClassHelper, ctnRecordHelper, ctnTypeHelper: + if + Assigned(StartNode.Parent) and (StartNode.Parent.Desc = ctnTypeDefinition) + then + Helpers.AddFromHelperNode(StartNode, Self, False); + ctnUsesSection: + FindHelpersInUsesSection(StartNode, Helpers); + end; + StartNode := SearchNextNode; + end; +end; + +procedure TFindDeclarationTool.FindHelpersInContext( + Params: TFindDeclarationParams); +begin + FindHelpersInContext(Params.ContextNode, Params.Helpers); +end; + +procedure TFindDeclarationTool.FindHelpersInInterface( + AskingTool: TFindDeclarationTool; Helpers: THelpersList); +begin + // build tree for pascal source + if not BuildInterfaceIdentifierCache(true) then exit; + if (AskingTool<>Self) and (AskingTool<>nil) then + begin + AskingTool.AddToolDependency(Self); + Helpers.AddFromList(FInterfaceHelperCache); + end; +end; + +procedure TFindDeclarationTool.FindHelpersInUsesSection( + UsesNode: TCodeTreeNode; Helpers: THelpersList); +var + NewCodeTool: TFindDeclarationTool; + Node: TCodeTreeNode; + +var + AnUnitName: string; + InFilename: string; +begin + // search in units + Node:=UsesNode.LastChild; + while Node<>nil do begin + AnUnitName:=ExtractUsedUnitName(Node,@InFilename); + if AnUnitName<>'' then begin + NewCodeTool:=FindCodeToolForUsedUnit(AnUnitName,InFilename,false); + if NewCodeTool<>nil then begin + // search the identifier in the interface of the used unit + NewCodeTool.FindHelpersInInterface(Self,Helpers); + end; + end; + Node:=Node.PriorBrother; + end; +end; + function TFindDeclarationTool.FindContextClassAndAncestors( const CursorPos: TCodeXYPosition; var ListOfPFindContext: TFPList ): boolean; @@ -4559,7 +5040,7 @@ begin Params.SetResult(AncestorContext); // check result - if not (Params.NewNode.Desc in [ctnClass,ctnClassInterface]) + if not (Params.NewNode.Desc in [ctnClass,ctnClassInterface,ctnClassHelper,ctnRecordHelper,ctnTypeHelper]) then RaiseBaseClassNotFound; end; @@ -4667,10 +5148,10 @@ var else begin // find declaration if Params=nil then - Params:=TFindDeclarationParams.Create + Params:=TFindDeclarationParams.Create(Self, CursorNode) else Params.Clear; - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfIgnoreCurContextNode]; Params.ContextNode:=CursorNode; //debugln(copy(Src,Params.ContextNode.StartPos,200)); @@ -5209,7 +5690,7 @@ begin if TargetTool=nil then RaiseException('TargetTool=nil'); TargetTool.BuildInterfaceIdentifierCache(true); - refs:=TFindUsedUnitReferences.Create; + refs:=TFindUsedUnitReferences.Create(Self, FindLastNode); try refs.TargetTool:=TargetTool; refs.TargetUnitName:=TargetTool.GetSourceName(false); @@ -5493,9 +5974,10 @@ function TFindDeclarationTool.FindIdentifierInClassOfMethod( } var ClassNameAtom: TAtomPosition; - OldInput: TFindDeclarationInput; + OldFlags: TFindDeclarationFlags; IdentFoundResult: TIdentifierFoundResult; CurClassNode: TCodeTreeNode; + ForExprType: TExpressionType; begin {$IFDEF CheckNodeTool}CheckNodeTool(ProcContextNode);{$ENDIF} Result:=false; @@ -5520,7 +6002,7 @@ begin CurClassNode:=FindClassOfMethod(ProcContextNode,true,true); repeat // search identifier in class - Params.Save(OldInput); + OldFlags := Params.Flags; Params.Flags:=[fdfSearchInAncestors] +(fdfGlobalsSameIdent*Params.Flags) -[fdfExceptionOnNotFound]; @@ -5528,8 +6010,21 @@ begin {$IFDEF ShowTriedContexts} DebugLn('[TFindDeclarationTool.FindIdentifierInClassOfMethod] searching identifier in class of method Identifier=',GetIdentifier(Params.Identifier)); {$ENDIF} - Result:=FindIdentifierInContext(Params); - Params.Load(OldInput,true); + if (fdfSearchInHelpers in Params.Flags) and + (CurClassNode.Desc in [ctnClassHelper,ctnRecordHelper]) and + (Params.Helpers.Count > 0) + then//override current helper for the type and search in that type + begin + ForExprType := Params.Helpers.AddFromHelperNode(CurClassNode, Self, True).ForExprType; + if (ForExprType.Desc = xtContext) and (ForExprType.Context.Tool<>nil) and + (ForExprType.Context.Node<>nil) + then begin + Params.ContextNode:=ForExprType.Context.Node; + Result:=ForExprType.Context.Tool.FindIdentifierInContext(Params); + end; + end else + Result:=FindIdentifierInContext(Params); + Params.Flags := OldFlags; if Result and Params.IsFoundProcFinal then exit; // in a nested class, continue search in enclosing class repeat @@ -5557,6 +6052,14 @@ begin end; end; +function TFindDeclarationTool.FindIdentifierInContext( + Params: TFindDeclarationParams): boolean; +var + IdentFoundResult: TIdentifierFoundResult; +begin + Result := FindIdentifierInContext(Params, IdentFoundResult{%H-}); +end; + function TFindDeclarationTool.FindClassOfMethod(ProcNode: TCodeTreeNode; FindClassContext, ExceptionOnNotFound: boolean): TCodeTreeNode; var @@ -5587,7 +6090,7 @@ begin Result:=nil; if ProcNode.Desc=ctnProcedureHead then ProcNode:=ProcNode.Parent; - if ProcNode.Parent.Desc in AllClassSections then begin + if (ProcNode.Parent<>nil) and (ProcNode.Parent.Desc in AllClassSections) then begin CurClassNode:=ProcNode.Parent.Parent; if FindClassContext then begin // return the class node @@ -6054,7 +6557,8 @@ begin end; function TFindDeclarationTool.FindIdentifierInAncestors( - ClassNode: TCodeTreeNode; Params: TFindDeclarationParams): boolean; + ClassNode: TCodeTreeNode; Params: TFindDeclarationParams; + var IdentFoundResult: TIdentifierFoundResult): boolean; { this function is internally used by FindIdentifierInContext and FindBaseTypeOfNode } @@ -6062,13 +6566,15 @@ function TFindDeclarationTool.FindIdentifierInAncestors( function Search(AncestorTool: TFindDeclarationTool; AncestorClassNode: TCodeTreeNode): boolean; var - OldInput: TFindDeclarationInput; + OldFlags: TFindDeclarationFlags; begin - Params.Save(OldInput); + OldFlags := Params.Flags; Params.ContextNode:=AncestorClassNode; - Params.Flags:=Params.Flags-[fdfIgnoreCurContextNode,fdfSearchInParentNodes]+[fdfSearchInAncestors]; - Result:=AncestorTool.FindIdentifierInContext(Params); - Params.Load(OldInput,true); + Params.Flags:=Params.Flags + -[fdfIgnoreCurContextNode,fdfSearchInParentNodes] + +[fdfSearchInAncestors]; + Result:=AncestorTool.FindIdentifierInContext(Params,IdentFoundResult); + Params.Flags := OldFlags; end; var @@ -6570,6 +7076,10 @@ function TFindDeclarationTool.BuildInterfaceIdentifierCache( FInterfaceIdentifierCache.Add(@Src[Node.StartPos],Node,Node.StartPos); ScanForEnums(Node); ScanForExtendedClass(Node); + if (Node.Desc = ctnTypeDefinition) and + Assigned(Node.FirstChild) and (Node.FirstChild.Desc in [ctnClassHelper, ctnRecordHelper, ctnTypeHelper]) + then + FInterfaceHelperCache.AddFromHelperNode(Node.FirstChild, Self, True); end; ctnGenericType: if Node.FirstChild<>nil then begin @@ -6631,6 +7141,10 @@ begin else FInterfaceIdentifierCache.Clear; FInterfaceIdentifierCache.Complete:=true; + if FInterfaceHelperCache=nil then + FInterfaceHelperCache:=THelpersList.Create + else + FInterfaceHelperCache.Clear; // add unit node MoveCursorToNodeStart(Tree.Root); @@ -6758,7 +7272,7 @@ begin if TypeNode.Desc=ctnIdentifier then begin // resolve type //debugln(['TFindDeclarationTool.FindIdentifierInTypeOfConstant ']); - TypeParams:=TFindDeclarationParams.Create; + TypeParams:=TFindDeclarationParams.Create(Params.Helpers); try TypeParams.ContextNode:=TypeNode; TypeParams.SetIdentifier(Self,nil,nil); @@ -7221,7 +7735,7 @@ var // typeless property => search in ancestors: it can be property with parameters Params.Save(OldInput); Params.SetIdentifier(Tool,@Tool.Src[Tool.CurPos.StartPos],nil); - Params.Flags:=[fdfSearchInAncestors]; + Params.Flags:=[fdfSearchInAncestors,fdfSearchInHelpers]; if Tool.FindIdentifierInAncestors(Node.Parent.Parent,Params) then begin Tool:=Params.NewCodeTool; Node:=Params.NewNode; @@ -7286,6 +7800,7 @@ var Context: TFindContext; IsEnd: Boolean; SearchForwardToo: Boolean; + NewTool: TFindDeclarationTool; begin // for example 'AnObject[3]' @@ -7304,12 +7819,27 @@ var while (ProcNode<>nil) do begin if (ProcNode.Desc=ctnProcedure) and NodeIsMethodBody(ProcNode) then begin - ResultNode:=FindClassOfMethod(ProcNode,not IsEnd, + ResultNode:=FindClassOfMethod(ProcNode,True, fdfExceptionOnNotFound in Params.Flags); - ExprType.Desc:=xtContext; - ExprType.Context.Tool:=Self; + if (ResultNode<>nil) and + (ResultNode.Desc in [ctnClassHelper,ctnRecordHelper,ctnTypeHelper]) + then//Self is helper -> return extended type + begin + ExprType := FindExtendedExprOfHelper(ResultNode); + ResultNode := ExprType.Context.Node; + end else + begin//Self is class/record + if (ResultNode<>nil) and (ResultNode.Parent<>nil) then + begin + ExprType.Desc:=xtContext; + ExprType.Context.Tool:=Self; + end else + ExprType := CleanExpressionType; + end; + if IsEnd and (ResultNode<>nil) then + ResultNode := ResultNode.Parent; ExprType.Context.Node:=ResultNode; - IdentFound:=ResultNode<>nil; + IdentFound:=ExprType.Desc<>xtNone; break; end; ProcNode:=ProcNode.Parent; @@ -7355,85 +7885,110 @@ var Params.Save(OldInput); // build new param flags for sub identifiers - Params.Flags:=[fdfSearchInAncestors,fdfExceptionOnNotFound] + Params.Flags:=[fdfSearchInAncestors,fdfExceptionOnNotFound,fdfSearchInHelpers] +(fdfGlobals*Params.Flags); if IsStart then Context:=CreateFindContext(Self,StartNode) else Context:=ExprType.Context; - Params.ContextNode:=Context.Node; - SearchForwardToo:=false; - if Context.Node=StartNode then begin - // there is no special context -> search in parent contexts too - Params.Flags:=Params.Flags+[fdfSearchInParentNodes,fdfIgnoreCurContextNode]; - // check if searching forward too - if CanBeForwardDefined then begin - SearchForwardToo:=true; - Params.Flags:=Params.Flags-[fdfExceptionOnNotFound]; - end; - end else begin - // only search in special context - Params.Flags:=Params.Flags+[fdfIgnoreUsedUnits]; - if Context.Node.Desc=ctnImplementation then - Params.Flags:=Params.Flags+[fdfSearchInParentNodes]; - end; - // check identifier for overloaded procs - if (IsEnd and (fdfIgnoreOverloadedProcs in StartFlags)) - then - Include(Params.Flags,fdfIgnoreOverloadedProcs); - - Params.SetIdentifier(Self,@Src[CurAtom.StartPos],@CheckSrcIdentifier); - - // search ... - {$IFDEF ShowExprEval} - Dbgout([' FindExpressionTypeOfTerm ResolveIdentifier backward ',BoolToStr(IsStart,'Main','Sub'),'Ident="',GetIdentifier(Params.Identifier),'" ContextNode="',Params.ContextNode.DescAsString,'" "',dbgstr(Context.Tool.Src,Params.ContextNode.StartPos,15),'" ',dbgs(Params.Flags)]); - {$ENDIF} - ExprType.Desc:=xtNone; - // first search backwards - if Context.Tool.FindIdentifierInContext(Params) then begin - ExprType.Desc:=xtContext; - end else if SearchForwardToo then begin - // then search forwards - Params.Load(OldInput,false); - Params.SetIdentifier(Self,@Src[CurAtom.StartPos],@CheckSrcIdentifier); - Params.Flags:=[fdfSearchInParentNodes,fdfExceptionOnNotFound, - fdfIgnoreCurContextNode,fdfSearchForward] - +(fdfGlobals*Params.Flags); - Params.ContextNode:=Context.Node; - {$IFDEF ShowExprEval} - DebugLn([' FindExpressionTypeOfTerm ResolveIdentifier forward SubIdent="',GetIdentifier(Params.Identifier),'" ContextNode="',Params.ContextNode.DescAsString,'" "',dbgstr(Context.Tool.Src,Params.ContextNode.StartPos,15),'" ',dbgs(Params.Flags)]); - {$ENDIF} - if FindIdentifierInContext(Params) then begin - ExprType.Desc:=xtContext; - end; - end; - if ExprType.Desc=xtContext then begin - // identifier found - if Params.NewCodeTool.NodeIsConstructor(Params.NewNode) then begin - // identifier is a constructor - if (Context.Node.Desc in AllClassObjects) then begin - if (not IsEnd) or (not (fdfFindVariable in StartFlags)) then begin - // examples: - // TMyClass.Create. - // :=TMyClass.Create; - // use this class (the constructor can be defined in the ancestor) - ExprType.Context:=Context; - Params.Load(OldInput,true); - exit; - end; + if (Context.Node = nil) then + begin + if (ExprType.Desc in xtAllPredefinedTypes) then + begin + //no problem, we found predefined basic type (e.g. string) without a context! + //find class helpers! + Context:=CreateFindContext(Self,StartNode); + if Context.Tool.FindIdentifierInBasicTypeHelpers(ExprType.Desc, Params, NewTool) then + begin + ExprType.Desc:=xtContext; + ExprType.SubDesc:=xtNone; + ExprType.Context.Tool := NewTool; + ExprType.Context.Node := Params.NewNode; end; end; - ExprType.Context:=CreateFindContext(Params); - Params.Load(OldInput,true); - end else begin - // predefined identifier - Params.Load(OldInput,true); - ExprType:=FindExpressionTypeOfPredefinedIdentifier(CurAtom.StartPos, - Params); - {$IFDEF CheckNodeTool} - if ExprType.Desc=xtContext then - ExprType.Context.Tool.CheckNodeTool(ExprType.Context.Node); + end else + begin + Params.ContextNode:=Context.Node; + SearchForwardToo:=false; + if Context.Node=StartNode then begin + // there is no special context -> search in parent contexts too + Params.Flags:=Params.Flags+[fdfSearchInParentNodes,fdfIgnoreCurContextNode]; + // check if searching forward too + if CanBeForwardDefined then begin + SearchForwardToo:=true; + Params.Flags:=Params.Flags-[fdfExceptionOnNotFound]; + end; + end else begin + // only search in special context + Params.Flags:=Params.Flags+[fdfIgnoreUsedUnits]; + if Assigned(Context.Node) and (Context.Node.Desc=ctnImplementation) then + Params.Flags:=Params.Flags+[fdfSearchInParentNodes]; + end; + + // check identifier for overloaded procs + if (IsEnd and (fdfIgnoreOverloadedProcs in StartFlags)) + then + Include(Params.Flags,fdfIgnoreOverloadedProcs); + + Params.SetIdentifier(Self,@Src[CurAtom.StartPos],@CheckSrcIdentifier); + + // search ... + {$IFDEF ShowExprEval} + Dbgout([' FindExpressionTypeOfTerm ResolveIdentifier backward ',BoolToStr(IsStart,'Main','Sub'),'Ident="',GetIdentifier(Params.Identifier),'" ContextNode="',Params.ContextNode.DescAsString,'" "',dbgstr(Context.Tool.Src,Params.ContextNode.StartPos,15),'" ',dbgs(Params.Flags)]); + {$ENDIF} + ExprType.Desc:=xtNone; + // first search backwards + if Context.Tool.FindIdentifierInContext(Params) then begin + ExprType.Desc:=xtContext; + end else if SearchForwardToo then begin + // then search forwards + Params.Load(OldInput,false); + Params.SetIdentifier(Self,@Src[CurAtom.StartPos],@CheckSrcIdentifier); + Params.Flags:=[fdfSearchInParentNodes,fdfExceptionOnNotFound, + fdfIgnoreCurContextNode,fdfSearchForward] + +(fdfGlobals*Params.Flags); + Params.ContextNode:=Context.Node; + {$IFDEF ShowExprEval} + DebugLn([' FindExpressionTypeOfTerm ResolveIdentifier forward SubIdent="',GetIdentifier(Params.Identifier),'" ContextNode="',Params.ContextNode.DescAsString,'" "',dbgstr(Context.Tool.Src,Params.ContextNode.StartPos,15),'" ',dbgs(Params.Flags)]); + {$ENDIF} + if FindIdentifierInContext(Params) then begin + ExprType.Desc:=xtContext; + end; + end; + if ExprType.Desc=xtContext then begin + // identifier found + if Params.NewCodeTool.NodeIsConstructor(Params.NewNode) then begin + // identifier is a constructor + if (Context.Node.Desc in AllClassObjects) then begin + if (not IsEnd) or (not (fdfFindVariable in StartFlags)) then begin + // examples: + // TMyClass.Create. + // :=TMyClass.Create; + // use this class (the constructor can be defined in the ancestor) + ExprType.Context:=Context; + Params.Load(OldInput,true); + exit; + end; + end; + end; + ExprType.Context:=CreateFindContext(Params); + Params.Load(OldInput,true); + end else begin + // predefined identifier + Params.Load(OldInput,true); + ExprType:=FindExpressionTypeOfPredefinedIdentifier(CurAtom.StartPos, + Params); + {$IFDEF CheckNodeTool} + if ExprType.Desc=xtContext then + ExprType.Context.Tool.CheckNodeTool(ExprType.Context.Node); + {$ENDIF} + end; + + // ToDo: check if identifier in 'Protected' section + + {$IFDEF ShowExprEval} + DebugLn([' FindExpressionTypeOfTerm ResolveIdentifier END Ident="',dbgstr(Src,StartPos,CurAtom.EndPos-StartPos),'" Expr=',ExprTypeToString(ExprType)]); {$ENDIF} end; @@ -7534,7 +8089,9 @@ var RaiseIdentExpected; end; ResolveChildren; - if (ExprType.Context.Node=nil) then begin + if ExprType.Desc in xtAllPredefinedTypes then begin + //Lazarus supports record helpers for basic types (string) as well (with TYPEHELPERS modeswitch!). + end else if (ExprType.Context.Node=nil) then begin MoveCursorToCleanPos(CurAtom.StartPos); ReadNextAtom; RaiseIllegalQualifierFound; @@ -7701,6 +8258,7 @@ var ExprType.Context.Node.FirstChild); ctnClass, ctnClassInterface, ctnDispinterface, ctnObject, ctnRecordType, + ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnObjCClass, ctnObjCCategory, ctnObjCProtocol, ctnCPPClass: begin // search default property of the class / interface @@ -7804,6 +8362,8 @@ var Context: TFindContext; var DefProcNode: TCodeTreeNode; + HelperForExpr: TExpressionType; + SearchInHelpersInTheEnd: Boolean; begin if ExprType.Desc=xtNone then Context:=CreateFindContext(Self,StartNode) @@ -7848,6 +8408,24 @@ var ExprType.Desc:=xtContext; ExprType.Context:=CreateFindContext(Params); + + //helpers have different order -> first search in extended class and then in helper (applies only to inherited call) + SearchInHelpersInTheEnd := False; + if ClassNodeOfMethod.Desc in [ctnClassHelper,ctnRecordHelper] then + begin + if (ExprType.Context.Node<>nil) and (ExprType.Context.Tool<>nil) then//inherited helper found -> use it! + Params.Helpers.AddFromHelperNode(ExprType.Context.Node, ExprType.Context.Tool, True) + else//inherited helper not found -> delete current + Params.Helpers.DeleteHelperNode(ClassNodeOfMethod, Self); + + HelperForExpr := FindExtendedExprOfHelper(ClassNodeOfMethod); + if HelperForExpr.Desc = xtContext then + begin + ExprType.Context := HelperForExpr.Context; + SearchInHelpersInTheEnd := True; + end; + end; + if (not HasIdentifier) then begin // the keyword 'inherited' is the last atom if StartFlags*[fdfFindChildren,fdfFindVariable]=[fdfFindVariable] then begin @@ -7867,6 +8445,8 @@ var MoveCursorToCleanPos(CurAtom.StartPos); // search identifier only in class ancestor + if SearchInHelpersInTheEnd then + Params.Flags := Params.Flags + [fdfSearchInHelpersInTheEnd]; Params.Save(OldInput); Params.SetIdentifier(Self,@Src[CurPos.StartPos],@CheckSrcIdentifier); Params.ContextNode:=ExprType.Context.Node; @@ -7875,6 +8455,7 @@ var ExprType.Context.Tool.FindIdentifierInContext(Params); ExprType.Context:=CreateFindContext(Params); Params.Load(OldInput,true); + Params.Flags := Params.Flags - [fdfSearchInHelpersInTheEnd]; end; begin @@ -8292,7 +8873,7 @@ begin // array with explicit range // Low(array[SubRange]) has the type of the subrange Result.Context.Tool.MoveCursorToNodeStart(ParamNode.FirstChild); - SubParams:=TFindDeclarationParams.Create; + SubParams:=TFindDeclarationParams.Create(Params.Helpers); try SubParams.Flags:=fdfDefaultForExpressions; SubParams.ContextNode:=ParamNode; @@ -8322,7 +8903,7 @@ begin // return type is System.SEL NewTool:=FindCodeToolForUsedUnit('system','',true); if NewTool=nil then exit; - SubParams:=TFindDeclarationParams.Create; + SubParams:=TFindDeclarationParams.Create(Params.Helpers); try SubParams.Identifier:='SEL'#0; if (not NewTool.FindIdentifierInInterface(Self,SubParams)) @@ -9341,6 +9922,7 @@ begin case ExprNode.Desc of ctnClass, ctnClassInterface, ctnDispinterface, ctnObject, ctnRecordType, + ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnObjCClass, ctnObjCCategory, ctnObjCProtocol, ctnCPPClass: // check, if ExpressionType.Context descends from TargetContext if ContextIsDescendOf(ExpressionType.Context, @@ -9627,10 +10209,7 @@ begin if (Sender.CurPos.Flag=cafPoint) or (Sender.UpAtomIs('inherited')) then exit; //debugln(['TFindUsedUnitReferences.OnIdentifier Identifier=',GetIdentifier(Identifier),' at begin of term']); // find declaration - if refs.Params=nil then - refs.Params:=TFindDeclarationParams.Create - else - refs.Params.Clear; + refs.Params.Clear; refs.Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, fdfIgnoreCurContextNode]; refs.Params.ContextNode:=Node; @@ -9717,6 +10296,8 @@ begin FInterfaceIdentifierCache.Clear; FInterfaceIdentifierCache.Complete:=false; end; + if FInterfaceHelperCache<>nil then + FInterfaceHelperCache.Clear; inherited DoDeleteNodes(StartNode); end; @@ -9784,6 +10365,8 @@ destructor TFindDeclarationTool.Destroy; begin FInterfaceIdentifierCache.Free; FInterfaceIdentifierCache:=nil; + FInterfaceHelperCache.Free; + FInterfaceHelperCache:=nil; FDependsOnCodeTools.Free; FDependsOnCodeTools:=nil; FDependentCodeTools.Free; @@ -9942,6 +10525,9 @@ begin if FInterfaceIdentifierCache<>nil then Stats.Add('TFindDeclarationTool.FInterfaceIdentifierCache', FInterfaceIdentifierCache.CalcMemSize); + if FInterfaceHelperCache<>nil then + Stats.Add('TFindDeclarationTool.FInterfaceHelperCache', + FInterfaceHelperCache.CalcMemSize); if FFirstNodeCache<>nil then begin m:=0; NodeCache:=FFirstNodeCache; @@ -10270,7 +10856,7 @@ begin // pointer type end else begin ExprType:=CleanExpressionType; - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfTopLvlResolving,fdfFunctionResult]; ExprType:=FindExpressionResultType(Params,TermPos.StartPos,TermPos.EndPos, @AliasType); @@ -10307,7 +10893,7 @@ begin ExprType:=CleanExpressionType; TermExprType:=CleanExpressionType; Params.ContextNode:=CursorNode; - Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors, + Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers, fdfTopLvlResolving,fdfFunctionResult]; TermExprType:=FindExpressionResultType(Params,TermPos.StartPos,TermPos.EndPos); @@ -10332,10 +10918,10 @@ begin xtContext: begin case TermExprType.Context.Node.Desc of - ctnClass: + ctnClass, ctnRecordType, ctnClassHelper, ctnRecordHelper, ctnTypeHelper: begin if not TermExprType.Context.Tool.FindEnumeratorOfClass( - TermExprType.Context.Node,true,ExprType,@AliasType) + TermExprType.Context.Node,true,ExprType,@AliasType, Params.Helpers) then RaiseTermHasNoIterator; Result:=FindExprTypeAsString(ExprType,TermPos.StartPos,@AliasType); @@ -10427,7 +11013,7 @@ end; function TFindDeclarationTool.FindEnumeratorOfClass(ClassNode: TCodeTreeNode; ExceptionOnNotFound: boolean; out ExprType: TExpressionType; - AliasType: PFindContext): boolean; + AliasType: PFindContext; Helpers: THelpersList): boolean; var Params: TFindDeclarationParams; ProcTool: TFindDeclarationTool; @@ -10441,11 +11027,11 @@ begin if AliasType<>nil then AliasType^:=CleanFindContext; ExprType:=CleanExpressionType; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Helpers); try // search function 'GetEnumerator' Params.ContextNode:=ClassNode; - Params.Flags:=[fdfSearchInAncestors]; + Params.Flags:=[fdfSearchInAncestors,fdfSearchInHelpers]; Params.SetIdentifier(Self,'GetEnumerator',nil); {$IFDEF ShowForInEval} DebugLn(['TFindDeclarationTool.FindEnumeratorOfClass searching GetEnumerator for ',ExtractClassName(ClassNode,false),' ...']); @@ -10854,9 +11440,10 @@ begin // try to find a name ReadNextAtom; if CurPos.StartPos>SrcLen then exit; - Params:=TFindDeclarationParams.Create; + Node := FindDeepestNodeAtPos(CurPos.StartPos,true); + Params:=TFindDeclarationParams.Create(Self, Node); try - Params.ContextNode:=FindDeepestNodeAtPos(CurPos.StartPos,true); + Params.ContextNode:=Node; SubExprType:=FindExpressionResultType(Params,CurPos.StartPos,-1); finally Params.Free; @@ -11007,6 +11594,7 @@ begin end; ctnClass, ctnClassInterface, ctnDispinterface, ctnObject, ctnRecordType, + ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnObjCClass, ctnObjCCategory, ctnObjCProtocol, ctnCPPClass: if (FindContext.Node.Parent<>nil) and (FindContext.Node.Parent.Desc in [ctnTypeDefinition,ctnGenericType]) @@ -11150,6 +11738,26 @@ begin end; end; +function TFindDeclarationTool.FindExtendedExprOfHelper(HelperNode: TCodeTreeNode + ): TExpressionType; +var + ForNode: TCodeTreeNode; + Params: TFindDeclarationParams; +begin + ForNode := FindHelperForNode(HelperNode); + if Assigned(ForNode) and Assigned(ForNode.FirstChild) then + begin + Params:=TFindDeclarationParams.Create; + try + Params.Flags:=fdfDefaultForExpressions-[fdfSearchInHelpers,fdfSearchInAncestors]+[fdfTypeType]; + Params.ContextNode:=ForNode; + Result:=FindExpressionTypeOfTerm(ForNode.FirstChild.StartPos,ForNode.FirstChild.EndPos,Params,false); + finally + Params.Free; + end; + end else + Result := CleanExpressionType; +end; { TFindDeclarationParams } @@ -11222,16 +11830,23 @@ begin end; end; -constructor TFindDeclarationParams.Create; +constructor TFindDeclarationParams.Create(AHelpers: THelpersList); begin inherited Create; Clear; + FFreeHelpers := not Assigned(AHelpers); + if FFreeHelpers then + FHelpers := THelpersList.Create + else + FHelpers := AHelpers; end; destructor TFindDeclarationParams.Destroy; begin Clear; FreeFoundProc(FFoundProcStackFirst,true); + if FFreeHelpers then + FHelpers.Free; inherited Destroy; end; @@ -11342,6 +11957,15 @@ begin end; end; +constructor TFindDeclarationParams.Create(Tool: TFindDeclarationTool; + AContextNode: TCodeTreeNode); +begin + Create(nil);//helper list will be created + ContextNode := AContextNode; + if (Tool<> nil) and (ContextNode<>nil) then + Tool.FindHelpersInContext(Self); +end; + procedure TFindDeclarationParams.ClearInput; begin Flags:=[]; diff --git a/components/codetools/identcompletiontool.pas b/components/codetools/identcompletiontool.pas index 6d7c1e2838..6fa5612066 100644 --- a/components/codetools/identcompletiontool.pas +++ b/components/codetools/identcompletiontool.pas @@ -388,7 +388,7 @@ type ): TCodeXYPosition; procedure FindCollectionContext(Params: TFindDeclarationParams; IdentStartPos: integer; CursorNode: TCodeTreeNode; - out GatherContext: TFindContext; out ContextExprStartPos: LongInt; + out ExprType: TExpressionType; out ContextExprStartPos: LongInt; out StartInSubContext: Boolean); function CollectAllContexts(Params: TFindDeclarationParams; const FoundContext: TFindContext): TIdentifierFoundResult; @@ -1692,6 +1692,7 @@ begin case Node.Desc of ctnClass,ctnObject,ctnRecordType,ctnObjCCategory,ctnObjCClass, + ctnClassHelper, ctnRecordHelper, ctnTypeHelper, ctnClassPrivate,ctnClassProtected,ctnClassPublic,ctnClassPublished: begin Add('public'); @@ -1949,7 +1950,7 @@ end; procedure TIdentCompletionTool.FindCollectionContext( Params: TFindDeclarationParams; IdentStartPos: integer; CursorNode: TCodeTreeNode; - out GatherContext: TFindContext; + out ExprType: TExpressionType; out ContextExprStartPos: LongInt; out StartInSubContext: Boolean); @@ -1979,10 +1980,11 @@ procedure TIdentCompletionTool.FindCollectionContext( end; var - ExprType: TExpressionType; IgnoreCurContext: Boolean; + GatherContext: TFindContext; begin GatherContext:=CreateFindContext(Self,CursorNode); + ExprType := CleanExpressionType; IgnoreCurContext:=false; //DebugLn(['TIdentCompletionTool.FindCollectionContext IdentStartPos=',dbgstr(copy(Src,IdentStartPos,20)),' ',CursorNode.DescAsString]); @@ -2010,17 +2012,18 @@ begin Params.ContextNode:=CursorNode; Params.SetIdentifier(Self,nil,nil); Params.Flags:=[fdfExceptionOnNotFound, - fdfSearchInParentNodes,fdfSearchInAncestors]; + fdfSearchInParentNodes,fdfSearchInAncestors,fdfSearchInHelpers,fdfTypeType]; if IgnoreCurContext then Params.Flags:=Params.Flags+[fdfIgnoreCurContextNode]; ExprType:=FindExpressionTypeOfTerm(ContextExprStartPos,IdentStartPos, Params,false); - if (ExprType.Desc=xtContext) then begin + if (ExprType.Desc in xtAllIdentTypes) then begin GatherContext:=ExprType.Context; debugln(['TIdentCompletionTool.FindCollectionContext ',ExprTypeToString(ExprType)]); StartInSubContext:=true; end; end; + ExprType.Context := GatherContext; end; function TIdentCompletionTool.CollectAllContexts( @@ -2470,6 +2473,7 @@ var CursorContext: TFindContext; IdentStartXY: TCodeXYPosition; InFrontOfDirective: Boolean; + ExprType: TExpressionType; procedure CheckProcedureDeclarationContext; var @@ -2515,7 +2519,7 @@ begin Result:=false; ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create;//FindHelpersInContext called later try InitCollectIdentifiers(CursorPos,IdentifierList); IdentStartXY:=FindIdentifierStartPos(CursorPos); @@ -2523,6 +2527,8 @@ begin ParseSourceTillCollectionStart(IdentStartXY,CleanCursorPos,CursorNode, IdentStartPos,IdentEndPos); + Params.ContextNode:=CursorNode; + FindHelpersInContext(Params); if CleanCursorPos=0 then ; if IdentStartPos>0 then begin MoveCursorToCleanPos(IdentStartPos); @@ -2553,8 +2559,9 @@ begin GatherSourceNames(GatherContext); end else begin FindCollectionContext(Params,IdentStartPos,CursorNode, - GatherContext,ContextExprStartPos,StartInSubContext); + ExprType,ContextExprStartPos,StartInSubContext); + GatherContext := ExprType.Context; // find class and ancestors if existing (needed for protected identifiers) if GatherContext.Tool = Self then FindContextClassAndAncestors(IdentStartXY, FICTClassAndAncestors); @@ -2574,7 +2581,7 @@ begin // gather all identifiers in context Params.ContextNode:=GatherContext.Node; Params.SetIdentifier(Self,nil,@CollectAllIdentifiers); - Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable]; + Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers]; if (Params.ContextNode.Desc=ctnInterface) and StartInSubContext then Include(Params.Flags,fdfIgnoreUsedUnits); if not StartInSubContext then @@ -2588,6 +2595,15 @@ begin if GatherContext.Node.Desc=ctnIdentifier then Params.Flags:=Params.Flags+[fdfIgnoreCurContextNode]; GatherContext.Tool.FindIdentifierInContext(Params); + end else + if ExprType.Desc in xtAllIdentPredefinedTypes then + begin + // gather all identifiers in cursor context for basic types (strings etc.) + Params.ContextNode:=CursorNode; + Params.SetIdentifier(Self,nil,@CollectAllIdentifiers); + Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers]; + CurrentIdentifierList.Context:=GatherContext; + FindIdentifierInBasicTypeHelpers(ExprType.Desc, Params); end; // check for incomplete context @@ -2823,9 +2839,9 @@ var var VarNameAtom, ProcNameAtom: TAtomPosition; ParameterIndex: integer; - GatherContext: TFindContext; ContextExprStartPos: LongInt; StartInSubContext: Boolean; + ExprType: TExpressionType; begin Result:=false; // check if in a begin..end block @@ -2865,24 +2881,37 @@ var CurrentIdentifierContexts.EndPos:=SrcLen+1; FindCollectionContext(Params,ProcNameAtom.StartPos,CursorNode, - GatherContext,ContextExprStartPos,StartInSubContext); + ExprType,ContextExprStartPos,StartInSubContext); if ContextExprStartPos=0 then ; {$IFDEF VerboseCodeContext} - DebugLn(['CheckContextIsParameter StartInSubContext=',StartInSubContext,' ',GatherContext.Node.DescAsString,' "',copy(GatherContext.Tool.Src,GatherContext.Node.StartPos-20,25),'"']); + DebugLn(['CheckContextIsParameter StartInSubContext=',StartInSubContext,' ',ExprType.Context.Node.DescAsString,' "',copy(ExprType.Context.Tool.Src,GatherContext.Node.StartPos-20,25),'"']); {$ENDIF} // gather declarations of all parameter lists - Params.ContextNode:=GatherContext.Node; + if (ExprType.Context.Node = nil) or (ExprType.Context.Tool = nil) then + begin + if ExprType.Desc in xtAllIdentPredefinedTypes then + begin + ExprType.Context.Node := CursorNode; + ExprType.Context.Tool := Self; + end else + Exit; + end; + + Params.ContextNode:=ExprType.Context.Node; Params.SetIdentifier(Self,@Src[ProcNameAtom.StartPos],@CollectAllContexts); - Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable]; + Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers]; if not StartInSubContext then Include(Params.Flags,fdfSearchInParentNodes); - CurrentIdentifierList.Context:=GatherContext; + CurrentIdentifierList.Context:=ExprType.Context; {$IFDEF VerboseCodeContext} DebugLn('CheckContextIsParameter searching procedures, properties and variables ...'); {$ENDIF} - GatherContext.Tool.FindIdentifierInContext(Params); + if ExprType.Desc in xtAllIdentPredefinedTypes then + ExprType.Context.Tool.FindIdentifierInBasicTypeHelpers(ExprType.Desc, Params) + else + ExprType.Context.Tool.FindIdentifierInContext(Params); {$IFDEF VerboseCodeContext} DebugLn('CheckContextIsParameter END'); {$ENDIF} @@ -2900,11 +2929,13 @@ begin CurrentIdentifierContexts:=CodeContexts; ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create;//FindHelpersInContext called later try InitCollectIdentifiers(CursorPos,IdentifierList); ParseSourceTillCollectionStart(CursorPos,CleanCursorPos,CursorNode, IdentStartPos,IdentEndPos); + Params.ContextNode:=CursorNode; + FindHelpersInContext(Params); if IdentStartPos=0 then ; if IdentEndPos=0 then ; @@ -3212,7 +3243,7 @@ begin EndPos:=CleanCursorPos; //DebugLn(['TIdentCompletionTool.GetValuesOfCaseVariable Expr=',dbgstr(copy(Src,CaseAtom.EndPos,EndPos-CaseAtom.EndPos))]); - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Self, CursorNode); Params.ContextNode:=CursorNode; Params.Flags:=fdfDefaultForExpressions+[fdfFunctionResult]; ExprType:=FindExpressionTypeOfTerm(CaseAtom.EndPos,EndPos,Params,true); @@ -3598,7 +3629,7 @@ begin ANode:=Node; if (ANode<>nil) and (Tool<>nil) then begin Tool.ActivateGlobalWriteLock; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Tool, ANode); try if ANode.HasParentOfType(ctnGenericType) then exit; BaseExprType.Context:=Tool.FindBaseTypeOfNode(Params,ANode); diff --git a/components/codetools/languages/codetoolsstrconsts.ca.po b/components/codetools/languages/codetoolsstrconsts.ca.po index 2e1baab624..9867c6a7b6 100644 --- a/components/codetools/languages/codetoolsstrconsts.ca.po +++ b/components/codetools/languages/codetoolsstrconsts.ca.po @@ -431,6 +431,10 @@ msgstr "directori d'interfície del gtk2" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Directori de l'IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.cs.po b/components/codetools/languages/codetoolsstrconsts.cs.po index d95d9fe360..6e819f6fc1 100644 --- a/components/codetools/languages/codetoolsstrconsts.cs.po +++ b/components/codetools/languages/codetoolsstrconsts.cs.po @@ -432,6 +432,10 @@ msgstr "adresář rozhraní gtk2" msgid "HasError" msgstr "HasError" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Adresář IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.de.po b/components/codetools/languages/codetoolsstrconsts.de.po index 31a5a4f299..aa1cdc54b9 100644 --- a/components/codetools/languages/codetoolsstrconsts.de.po +++ b/components/codetools/languages/codetoolsstrconsts.de.po @@ -432,6 +432,10 @@ msgstr "Gtk-Interface-Verzeichnis" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "IDE-Verzeichnis" diff --git a/components/codetools/languages/codetoolsstrconsts.es.po b/components/codetools/languages/codetoolsstrconsts.es.po index 6cf3d7e5ff..ff29cfa135 100644 --- a/components/codetools/languages/codetoolsstrconsts.es.po +++ b/components/codetools/languages/codetoolsstrconsts.es.po @@ -427,6 +427,10 @@ msgstr "directorio de la interfase gtk2" msgid "HasError" msgstr "EsError" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Directorio del IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.fi.po b/components/codetools/languages/codetoolsstrconsts.fi.po index 072c778826..4eea2986e5 100644 --- a/components/codetools/languages/codetoolsstrconsts.fi.po +++ b/components/codetools/languages/codetoolsstrconsts.fi.po @@ -422,6 +422,10 @@ msgstr "gtk2 rajapinnan hakemisto" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "IDE hakemisto" @@ -691,6 +695,7 @@ msgid "operand expected, but %s found" msgstr "odotettiin operandia, mutta saatiin %s" #: codetoolsstrconsts.ctsoperatorexpectedbutatomfound +msgctxt "codetoolsstrconsts.ctsoperatorexpectedbutatomfound" msgid "operator expected, but %s found" msgstr "odotettiin operaattoria, mutta saatiin %s" @@ -703,6 +708,7 @@ msgid "operator expected but %s found" msgstr "odotettiin operaattoria, mutta saatiin %s" #: codetoolsstrconsts.ctsoperatorexpectedbutfound2 +msgctxt "codetoolsstrconsts.ctsoperatorexpectedbutfound2" msgid "operator expected, but %s found" msgstr "odotettiin operaattoria, mutta saatiin %s" diff --git a/components/codetools/languages/codetoolsstrconsts.fr.po b/components/codetools/languages/codetoolsstrconsts.fr.po index 69645e8750..ff1cb48ddc 100644 --- a/components/codetools/languages/codetoolsstrconsts.fr.po +++ b/components/codetools/languages/codetoolsstrconsts.fr.po @@ -429,6 +429,10 @@ msgstr "répertoire d'interface pour gtk2" msgid "HasError" msgstr "Contient une erreur" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Répertoire de l'EDI" @@ -954,3 +958,4 @@ msgstr "Répertoire des éléments graphiques (\"widgets\")" #: codetoolsstrconsts.ctswordnotfound msgid "\"%s\" not found" msgstr "\"%s\" non trouvé" + diff --git a/components/codetools/languages/codetoolsstrconsts.he.po b/components/codetools/languages/codetoolsstrconsts.he.po index 015c0dc7f9..4ace7098a6 100644 --- a/components/codetools/languages/codetoolsstrconsts.he.po +++ b/components/codetools/languages/codetoolsstrconsts.he.po @@ -431,6 +431,10 @@ msgstr "תיקיית הממשק של gtk2" msgid "HasError" msgstr "יש בו שגיאה" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "תיקיית ה IDE " diff --git a/components/codetools/languages/codetoolsstrconsts.hu.po b/components/codetools/languages/codetoolsstrconsts.hu.po index ff14d79ac5..d05f4c3daa 100644 --- a/components/codetools/languages/codetoolsstrconsts.hu.po +++ b/components/codetools/languages/codetoolsstrconsts.hu.po @@ -429,6 +429,10 @@ msgstr "gtk2 felület könyvtára" msgid "HasError" msgstr "Hibás" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "IDE könyvtára" @@ -954,3 +958,4 @@ msgstr "Vezérlőkészlet könyvtára" #: codetoolsstrconsts.ctswordnotfound msgid "\"%s\" not found" msgstr "\"%s\" nem található" + diff --git a/components/codetools/languages/codetoolsstrconsts.id.po b/components/codetools/languages/codetoolsstrconsts.id.po index 8dbe1e0001..62c6346681 100644 --- a/components/codetools/languages/codetoolsstrconsts.id.po +++ b/components/codetools/languages/codetoolsstrconsts.id.po @@ -432,6 +432,10 @@ msgstr "Direktori interface gtk2" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Direktori IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.it.po b/components/codetools/languages/codetoolsstrconsts.it.po index c0d037d7dc..ebd265e8cd 100644 --- a/components/codetools/languages/codetoolsstrconsts.it.po +++ b/components/codetools/languages/codetoolsstrconsts.it.po @@ -427,6 +427,10 @@ msgstr "gtk2 directory di interfaccia" msgid "HasError" msgstr "HasError" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Cartella dell'IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.lt.po b/components/codetools/languages/codetoolsstrconsts.lt.po index cdaaef12d1..4ab2d23ac2 100644 --- a/components/codetools/languages/codetoolsstrconsts.lt.po +++ b/components/codetools/languages/codetoolsstrconsts.lt.po @@ -432,6 +432,10 @@ msgstr "gtk2 interfeiso aplankas" msgid "HasError" msgstr "TuriKlaida" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "IKA aplankas" diff --git a/components/codetools/languages/codetoolsstrconsts.nl.po b/components/codetools/languages/codetoolsstrconsts.nl.po index 9ac17ce9e5..83228483dd 100644 --- a/components/codetools/languages/codetoolsstrconsts.nl.po +++ b/components/codetools/languages/codetoolsstrconsts.nl.po @@ -431,6 +431,10 @@ msgstr "" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "" diff --git a/components/codetools/languages/codetoolsstrconsts.pl.po b/components/codetools/languages/codetoolsstrconsts.pl.po index 4a3d171bcd..12fa0da8ca 100644 --- a/components/codetools/languages/codetoolsstrconsts.pl.po +++ b/components/codetools/languages/codetoolsstrconsts.pl.po @@ -435,6 +435,10 @@ msgstr "katalog interfejsu gtk2" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "" diff --git a/components/codetools/languages/codetoolsstrconsts.po b/components/codetools/languages/codetoolsstrconsts.po index 420f7aa114..eb8c2fe80c 100644 --- a/components/codetools/languages/codetoolsstrconsts.po +++ b/components/codetools/languages/codetoolsstrconsts.po @@ -422,6 +422,10 @@ msgstr "" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "" diff --git a/components/codetools/languages/codetoolsstrconsts.pt_BR.po b/components/codetools/languages/codetoolsstrconsts.pt_BR.po index a05403a60b..17f60357ec 100644 --- a/components/codetools/languages/codetoolsstrconsts.pt_BR.po +++ b/components/codetools/languages/codetoolsstrconsts.pt_BR.po @@ -431,6 +431,10 @@ msgstr "diretório de interface gtk2" msgid "HasError" msgstr "Há Erros" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Diretório do IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.ru.po b/components/codetools/languages/codetoolsstrconsts.ru.po index 19416a8ede..c6d61a5d18 100644 --- a/components/codetools/languages/codetoolsstrconsts.ru.po +++ b/components/codetools/languages/codetoolsstrconsts.ru.po @@ -429,6 +429,10 @@ msgstr "каталог интерфейса gtk2" msgid "HasError" msgstr "Ошибка" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Каталог IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.sk.po b/components/codetools/languages/codetoolsstrconsts.sk.po index f9083eced9..adaa5e5fe4 100644 --- a/components/codetools/languages/codetoolsstrconsts.sk.po +++ b/components/codetools/languages/codetoolsstrconsts.sk.po @@ -430,6 +430,10 @@ msgstr "" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "" diff --git a/components/codetools/languages/codetoolsstrconsts.uk.po b/components/codetools/languages/codetoolsstrconsts.uk.po index d54ed6e70e..b9180ad91b 100644 --- a/components/codetools/languages/codetoolsstrconsts.uk.po +++ b/components/codetools/languages/codetoolsstrconsts.uk.po @@ -432,6 +432,10 @@ msgstr "тека інтерфейсу gtk2" msgid "HasError" msgstr "HasError" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "Тека IDE" diff --git a/components/codetools/languages/codetoolsstrconsts.zh_CN.po b/components/codetools/languages/codetoolsstrconsts.zh_CN.po index 0cbd6b89d3..99362334af 100644 --- a/components/codetools/languages/codetoolsstrconsts.zh_CN.po +++ b/components/codetools/languages/codetoolsstrconsts.zh_CN.po @@ -434,6 +434,10 @@ msgstr "gtk2 接口目录" msgid "HasError" msgstr "" +#: codetoolsstrconsts.ctshelperisnotallowed +msgid "Helper after %s is not allowed" +msgstr "" + #: codetoolsstrconsts.ctsidedirectory msgid "IDE Directory" msgstr "IDE 目录" diff --git a/components/codetools/methodjumptool.pas b/components/codetools/methodjumptool.pas index ae72eb652a..9a9c75f08e 100644 --- a/components/codetools/methodjumptool.pas +++ b/components/codetools/methodjumptool.pas @@ -357,6 +357,7 @@ begin // first test if in a class ClassNode:=CursorNode.GetNodeOfTypes([ctnClass,ctnClassInterface, ctnDispinterface,ctnObject,ctnRecordType, + ctnClassHelper,ctnRecordHelper,ctnTypeHelper, ctnObjCClass,ctnObjCCategory,ctnObjCProtocol, ctnCPPClass]); if ClassNode<>nil then begin @@ -809,7 +810,7 @@ begin cmp:=false; end; if cmp and (phpIgnoreMethods in Attr) then begin - if (ANode.GetNodeOfTypes([ctnClass,ctnObject,ctnRecordType, + if (ANode.GetNodeOfTypes([ctnClass,ctnObject,ctnRecordType,ctnClassHelper,ctnRecordHelper,ctnTypeHelper, ctnObjCClass,ctnObjCCategory,ctnCPPClass])<>nil) or (ExtractClassNameOfProcNode(ANode,true)<>'') then diff --git a/components/codetools/pascalparsertool.pas b/components/codetools/pascalparsertool.pas index 8e1f7c1825..74e0a6aac9 100644 --- a/components/codetools/pascalparsertool.pas +++ b/components/codetools/pascalparsertool.pas @@ -277,6 +277,7 @@ type function FindSectionNodeAtPos(P: integer): TCodeTreeNode; function FindScanRangeNode(Range: TLinkScannerRange): TCodeTreeNode; function FindScanRangeNodeAtPos(P: integer): TCodeTreeNode; + function FindLastNode: TCodeTreeNode; function NodeHasParentOfType(ANode: TCodeTreeNode; NodeDesc: TCodeTreeNodeDesc): boolean; @@ -3542,7 +3543,7 @@ begin SaveRaiseExceptionWithHint; UndoReadNextAtom; EndChildNode; - end else if (CurNode.Desc in [ctnProgram,ctnLibrary,ctnImplementation]) then + end else if (CurNode<>nil) and (CurNode.Desc in [ctnProgram,ctnLibrary,ctnImplementation]) then begin ReadNextAtom; if (CurPos.Flag<>cafPoint) then @@ -4162,8 +4163,6 @@ begin end; end else begin // forward definition - if IntfDesc=ctnTypeHelper then - SaveRaiseException('forward defined type helpers are not allowed'); CurNode.SubDesc:=CurNode.SubDesc+ctnsForwardDeclaration; end; if CurPos.Flag=cafEND then begin @@ -4221,6 +4220,7 @@ var ClassDesc: TCodeTreeNodeDesc; ClassNode: TCodeTreeNode; IsHelper: Boolean; + HelperForNode: TCodeTreeNode; begin //debugln(['TPascalParserTool.KeyWordFuncTypeClass ',GetAtom,' ',CleanPosToStr(CurPos.StartPos)]); // class or 'class of' start found @@ -4236,10 +4236,12 @@ begin ClassDesc:=ctnObjCCategory else if UpAtomIs('CPPCLASS') then ClassDesc:=ctnCPPClass + else if UpAtomIs('TYPE') then + ClassDesc:=ctnTypeType else SaveRaiseStringExpectedButAtomFound('class'); ContextDesc:=CurNode.Desc; - if ClassDesc<>ctnRecordType then begin + if not(ClassDesc in [ctnRecordType, ctnTypeType]) then begin if not (ContextDesc in [ctnTypeDefinition,ctnGenericType]) then SaveRaiseExceptionFmt(ctsAnonymDefinitionsAreNotAllowed,[GetAtom]); @@ -4311,10 +4313,14 @@ begin end; end else if UpAtomIs('HELPER') then begin IsHelper:=true; - CreateChildNode; - CurNode.Desc:=ctnClassHelper; - CurNode.EndPos:=CurPos.EndPos; - EndChildNode; + case ClassDesc of + ctnClass: CurNode.Desc:=ctnClassHelper; + ctnRecordType: CurNode.Desc:=ctnRecordHelper; + ctnTypeType: CurNode.Desc:=ctnTypeHelper; + else + SaveRaiseExceptionFmt(ctsHelperIsNotAllowed,[GetAtom]); + end; + ClassDesc:=CurNode.Desc; ReadNextAtom; end; end; @@ -4328,14 +4334,21 @@ begin if not UpAtomIs('FOR') then SaveRaiseStringExpectedButAtomFound('for'); CreateChildNode; - CurNode.Desc:=ctnClassHelperFor; + CurNode.Desc:=ctnHelperFor; + HelperForNode:=CurNode; + CreateChildNode; + CurNode.Desc:=ctnIdentifier; repeat ReadNextAtom; + if CurNode.StartPos = HelperForNode.StartPos then + CurNode.StartPos:=CurPos.StartPos; AtomIsIdentifierSaveE; CurNode.EndPos:=CurPos.EndPos; + HelperForNode.EndPos:=CurPos.EndPos; ReadNextAtom; until CurPos.Flag<>cafPoint; EndChildNode; + EndChildNode; end; end; if CurPos.Flag=cafSemicolon then begin @@ -4614,38 +4627,23 @@ end; function TPascalParserTool.KeyWordFuncTypeType: boolean; // 'type identifier' +var + StartPos: Integer; begin - if not LastAtomIs(0,'=') then - SaveRaiseStringExpectedButAtomFound(ctsIdentifier); - CreateChildNode; - CurNode.Desc:=ctnTypeType; + StartPos := CurPos.StartPos; ReadNextAtom; - if UpAtomIs('HELPER') and (cmsTypeHelpers in Scanner.CompilerModeSwitches) then + if UpAtomIs('HELPER') then begin + UndoReadNextAtom; + Result := KeyWordFuncTypeClass; + end else begin - // type helper(inheritance) for typename - CurNode.Desc:=ctnTypeHelper; - // read inheritance - ReadNextAtom; - if (CurPos.Flag=cafRoundBracketOpen) then begin - // read inheritage brackets - ReadClassInheritance(true); - ReadNextAtom; - end; - // read 'FOR' - if not UpAtomIs('FOR') then - SaveRaiseStringExpectedButAtomFound('FOR'); - // read helperfor - ReadNextAtom; - AtomIsIdentifierE; CreateChildNode; - CurNode.Desc:=ctnClassHelperFor; - EndChildNode; - // read props and procs - ReadClassInterfaceContent; - end else begin + CurNode.StartPos:=StartPos; + CurNode.Desc:=ctnTypeType; Result:=ParseType(CurPos.StartPos); CurNode.EndPos:=CurPos.EndPos; EndChildNode; + Result:=true; end; end; @@ -5740,7 +5738,7 @@ begin exit; end; try - IsMethod:=ProcNode.Parent.Desc in (AllClasses+AllClassSections); + IsMethod:=(ProcNode.Parent<>nil) and (ProcNode.Parent.Desc in (AllClasses+AllClassSections)); MoveCursorToNodeStart(ProcNode); ReadNextAtom; if UpAtomIs('CLASS') then @@ -5868,6 +5866,13 @@ begin Result:=FindRootNode(ctnImplementation); end; +function TPascalParserTool.FindLastNode: TCodeTreeNode; +begin + Result := FindRootNode(ctnEndPoint); + if Result=nil then + Result := Tree.GetLastNode; +end; + function TPascalParserTool.FindImplementationUsesNode: TCodeTreeNode; begin Result:=Tree.Root; diff --git a/components/codetools/pascalreadertool.pas b/components/codetools/pascalreadertool.pas index 69fe3e1d87..9131e4ccab 100644 --- a/components/codetools/pascalreadertool.pas +++ b/components/codetools/pascalreadertool.pas @@ -199,6 +199,7 @@ type function ClassSectionNodeStartsWithWord(ANode: TCodeTreeNode): boolean; function IsClassNode(Node: TCodeTreeNode): boolean; // class, not object function FindInheritanceNode(ClassNode: TCodeTreeNode): TCodeTreeNode; + function FindHelperForNode(HelperNode: TCodeTreeNode): TCodeTreeNode; // records function ExtractRecordCaseType(RecordCaseNode: TCodeTreeNode): string; @@ -2797,6 +2798,16 @@ begin end; end; +function TPascalReaderTool.FindHelperForNode(HelperNode: TCodeTreeNode + ): TCodeTreeNode; +begin + Result:=HelperNode.FirstChild; + while (Result<>nil) and (Result.Desc = ctnClassInheritance) do + Result:=Result.NextBrother; + if (Result<>nil) and (Result.Desc<>ctnHelperFor) then + Result:=nil; +end; + function TPascalReaderTool.FindTypeOfForwardNode(TypeNode: TCodeTreeNode ): TCodeTreeNode; diff --git a/docs/Contributors.txt b/docs/Contributors.txt index 6881157816..e3317b7291 100644 --- a/docs/Contributors.txt +++ b/docs/Contributors.txt @@ -155,6 +155,7 @@ Mike Sapsard Mike Thompson Nikolay Ermolov Olivier Guilbaud +Ondrej Pokorny Patrick Chevalley Paul Ishenin Paul Michell diff --git a/ide/codebrowser.pas b/ide/codebrowser.pas index 3fedb54573..af94fb2d37 100644 --- a/ide/codebrowser.pas +++ b/ide/codebrowser.pas @@ -1952,7 +1952,8 @@ begin case CTNode.FirstChild.Desc of ctnClass,ctnClassInterface,ctnObject, ctnObjCClass,ctnObjCCategory,ctnObjCProtocol, - ctnCPPClass: + ctnCPPClass, + ctnClassHelper,ctnRecordHelper,ctnTypeHelper: begin case CTNode.FirstChild.Desc of ctnClassInterface: @@ -1967,6 +1968,12 @@ begin Description:=Description+' = objcprotocol'; ctnCPPClass: Description:=Description+' = cppclass'; + ctnClassHelper: + Description:=Description+' = class helper'; + ctnRecordHelper: + Description:=Description+' = record helper'; + ctnTypeHelper: + Description:=Description+' = type helper'; else Description:=Description+' = class'; end; diff --git a/ide/codecontextform.pas b/ide/codecontextform.pas index 6f5f7cc8c1..cd5a8f0f1d 100644 --- a/ide/codecontextform.pas +++ b/ide/codecontextform.pas @@ -378,7 +378,7 @@ procedure TCodeContextFrm.CreateHints(const CodeContexts: TCodeContextInfo); ExprNode: TCodeTreeNode; begin Result:=false; - Params:=TFindDeclarationParams.Create; + Params:=TFindDeclarationParams.Create(Tool, Node); try try Expr:=Tool.ConvertNodeToExpressionType(Node,Params); diff --git a/ide/codeexplorer.pas b/ide/codeexplorer.pas index 776e1e1c3e..4a64338776 100644 --- a/ide/codeexplorer.pas +++ b/ide/codeexplorer.pas @@ -179,6 +179,9 @@ type fSortCodeTool: TCodeTool; FUpdateCount: integer; ImgIDClass: Integer; + ImgIDClassInterface: Integer; + ImgIDRecord: Integer; + ImgIDHelper: Integer; ImgIDConst: Integer; ImgIDSection: Integer; ImgIDDefault: integer; @@ -489,6 +492,9 @@ begin ImgIDVariable := Imagelist1.AddResourceName(HInstance, 'ce_variable'); ImgIDConst := Imagelist1.AddResourceName(HInstance, 'ce_const'); ImgIDClass := Imagelist1.AddResourceName(HInstance, 'ce_class'); + ImgIDClassInterface := Imagelist1.AddResourceName(HInstance, 'ce_classinterface'); + ImgIDHelper := Imagelist1.AddResourceName(HInstance, 'ce_helper'); + ImgIDRecord := Imagelist1.AddResourceName(HInstance, 'ce_record'); ImgIDProcedure := Imagelist1.AddResourceName(HInstance, 'ce_procedure'); ImgIDFunction := Imagelist1.AddResourceName(HInstance, 'ce_function'); ImgIDProperty := Imagelist1.AddResourceName(HInstance, 'ce_property'); @@ -702,6 +708,8 @@ end; function TCodeExplorerView.GetCodeNodeDescription(ACodeTool: TCodeTool; CodeNode: TCodeTreeNode): string; +var + ClassIdentNode, HelperForNode, InhNode: TCodeTreeNode; begin Result:='?'; @@ -726,9 +734,27 @@ begin ctnResStrSection: Result:='Resourcestring'; - ctnTypeDefinition,ctnVarDefinition,ctnConstDefinition,ctnUseUnit: + ctnVarDefinition,ctnConstDefinition,ctnUseUnit: Result:=ACodeTool.ExtractIdentifier(CodeNode.StartPos); + ctnTypeDefinition: + begin + Result:=ACodeTool.ExtractIdentifier(CodeNode.StartPos); + ClassIdentNode := CodeNode.FirstChild; + if Assigned(ClassIdentNode) then + begin + if ClassIdentNode.Desc in [ctnClassHelper, ctnRecordHelper, ctnTypeHelper] then + HelperForNode := ACodeTool.FindHelperForNode(ClassIdentNode) + else + HelperForNode := nil; + InhNode:=ACodeTool.FindInheritanceNode(ClassIdentNode); + if InhNode<>nil then + Result:=Result+ACodeTool.ExtractNode(InhNode,[]); + if HelperForNode<>nil then + Result:=Result+' '+ACodeTool.ExtractNode(HelperForNode,[]); + end; + end; + ctnGenericType: Result:=ACodeTool.ExtractDefinitionName(CodeNode); @@ -809,9 +835,19 @@ begin ctnTypeSection: Result:=ImgIDSection; ctnTypeDefinition: begin - if (CodeNode.FirstChild <> nil) - and (CodeNode.FirstChild.Desc in AllClasses) then - Result := ImgIDClass + if (CodeNode.FirstChild <> nil) then + case CodeNode.FirstChild.Desc of + ctnClassInterface,ctnDispinterface,ctnObjCProtocol: + Result := ImgIDClassInterface; + ctnClass,ctnObjCClass,ctnObjCCategory,ctnCPPClass: + Result := ImgIDClass; + ctnObject,ctnRecordType: + Result := ImgIDRecord; + ctnClassHelper,ctnRecordHelper,ctnTypeHelper: + Result := ImgIDHelper; + else + Result := ImgIDType; + end else Result := ImgIDType; end; @@ -819,9 +855,14 @@ begin ctnVarDefinition: Result:=ImgIDVariable; ctnConstSection,ctnResStrSection: Result:=ImgIDSection; ctnConstDefinition: Result:=ImgIDConst; - ctnClass,ctnClassInterface,ctnObject, - ctnObjCClass,ctnObjCProtocol,ctnObjCCategory,ctnCPPClass: + ctnClassInterface,ctnDispinterface,ctnObjCProtocol: + Result := ImgIDClassInterface; + ctnClass,ctnObject, + ctnObjCClass,ctnObjCCategory,ctnCPPClass: Result:=ImgIDClass; + ctnRecordType: Result:=ImgIDRecord; + ctnClassHelper,ctnRecordHelper,ctnTypeHelper: + Result:=ImgIDHelper; ctnProcedure: if Tool.NodeIsFunction(CodeNode) then Result:=ImgIDFunction else @@ -905,8 +946,10 @@ begin if CodeNode.Desc=ctnEnumerationType then ShowNode:=false; - // don't show special nodes - if CodeNode.Desc in [ctnEndPoint] then + // don't show end node and class modification nodes + if CodeNode.Desc in [ctnEndPoint,ctnClassInheritance,ctnHelperFor, + ctnClassAbstract,ctnClassExternal,ctnClassSealed] + then ShowNode:=false; // don't show class visibility section nodes diff --git a/ide/codehelp.pas b/ide/codehelp.pas index 1b4ade4ec9..8674b8c633 100644 --- a/ide/codehelp.pas +++ b/ide/codehelp.pas @@ -310,12 +310,18 @@ type XYPos: TCodeXYPosition; Options: TCodeHelpHintOptions; out BaseURL, HTMLHint: string; out CacheWasUsed: boolean): TCodeHelpParseResult; + function GetHTMLHintForExpr(CTExprType: TExpressionType; + XYPos: TCodeXYPosition; Options: TCodeHelpHintOptions; + out BaseURL, HTMLHint: string; + out CacheWasUsed: boolean): TCodeHelpParseResult; function GetHTMLHintForUnit(AUnitName, InFilename: string; BaseDir: string; Options: TCodeHelpHintOptions; out BaseURL, HTMLHint: string; out CacheWasUsed: boolean): TCodeHelpParseResult; function GetHTMLDeclarationHeader(Tool: TFindDeclarationTool; Node: TCodeTreeNode; XYPos: TCodeXYPosition): string; + function GetHTMLDeclarationHeader(Tool: TFindDeclarationTool; + Node: TCodeTreeNode; Desc: TExpressionTypeDesc; XYPos: TCodeXYPosition): string; function GetPasDocCommentsAsHTML(Tool: TFindDeclarationTool; Node: TCodeTreeNode): string; function GetFPDocNodeAsHTML(FPDocFile: TLazFPDocFile; DOMNode: TDOMNode): string; function TextToHTML(Txt: string): string; @@ -2363,10 +2369,9 @@ function TCodeHelpManager.GetHTMLHint(Code: TCodeBuffer; X, Y: integer; out CacheWasUsed: boolean): TCodeHelpParseResult; var CursorPos: TCodeXYPosition; - CTTool: TFindDeclarationTool; - CTNode: TCodeTreeNode; XYPos: TCodeXYPosition; TopLine: integer; + CTExprType: TExpressionType; begin Result:=chprFailed; BaseURL:='lazdoc://'; @@ -2381,17 +2386,18 @@ begin try // find declaration if not CodeToolBoss.CurCodeTool.FindDeclaration(CursorPos, - DefaultFindSmartHintFlags+[fsfSearchSourceName],CTTool,CTNode,XYPos,TopLine) + DefaultFindSmartHintFlags+[fsfSearchSourceName],CTExprType,XYPos,TopLine) then exit; - if (CTNode=nil) then begin + if (CTExprType.Desc=xtContext) and (CTExprType.Context.Node=nil) then begin // codetools found a source file, not a declararion debugln(['TCodeHelpManager.GetHTMLHint not a declaration']); exit; end; - Result:=GetHTMLHintForNode(CTTool,CTNode,XYPos,Options,BaseURL,HTMLHint,CacheWasUsed); + Result:=GetHTMLHintForExpr(CTExprType,XYPos,Options,BaseURL,HTMLHint,CacheWasUsed); // Property details are like "published property TType.PropName:Integer" - PropDetails:=CTTool.GetSmartHint(CTNode,XYPos,false); + if (CTExprType.Desc=xtContext) and (CTExprType.Context.Tool<>nil) then + PropDetails:=CTExprType.Context.Tool.GetSmartHint(CTExprType.Context.Node,XYPos,false); except on E: ECodeToolError do begin //debugln(['TCodeHelpManager.GetHTMLHint ECodeToolError: ',E.Message]); @@ -2403,9 +2409,9 @@ begin end; end; -function TCodeHelpManager.GetHTMLHintForNode(CTTool: TFindDeclarationTool; - CTNode: TCodeTreeNode; XYPos: TCodeXYPosition; Options: TCodeHelpHintOptions; - out BaseURL, HTMLHint: string; out CacheWasUsed: boolean): TCodeHelpParseResult; +function TCodeHelpManager.GetHTMLHintForExpr(CTExprType: TExpressionType; + XYPos: TCodeXYPosition; Options: TCodeHelpHintOptions; out BaseURL, + HTMLHint: string; out CacheWasUsed: boolean): TCodeHelpParseResult; var aTopLine: integer; ListOfPCodeXYPosition: TFPList; @@ -2423,11 +2429,22 @@ var n: Integer; s: String; Cmd: TKeyCommandRelation; + CTTool: TFindDeclarationTool; + CTNode: TCodeTreeNode; begin Result:=chprFailed; BaseURL:='lazdoc://'; HTMLHint:=''; CacheWasUsed:=true; + AnOwner := nil; + + if (CTExprType.Desc in xtAllPredefinedTypes) then + CTExprType.Context.Tool := CodeToolBoss.CurCodeTool.FindCodeToolForUsedUnit('system','',false); + CTTool := CTExprType.Context.Tool; + CTNode := CTExprType.Context.Node; + + if CTTool=nil then + Exit(chprFailed); ListOfPCodeXYPosition:=nil; Complete:=not (chhoSmallStep in Options); @@ -2435,10 +2452,15 @@ begin try try if chhoDeclarationHeader in Options then - HTMLHint:=HTMLHint+GetHTMLDeclarationHeader(CTTool,CTNode,XYPos); + HTMLHint:=HTMLHint+GetHTMLDeclarationHeader(CTTool,CTNode,CTExprType.Desc,XYPos); for n:=1 to 30 do begin - ElementName:=CodeNodeToElementName(CTTool,CTNode); + if (CTExprType.Desc=xtContext) and (CTNode<>nil) then + ElementName:=CodeNodeToElementName(CTTool,CTNode) + else if (CTExprType.Desc in xtAllPredefinedTypes) then + ElementName:=ExpressionTypeDescNames[CTExprType.Desc] + else + break; //debugln(['TCodeHelpManager.GetHTMLHintForNode ElementName=',ElementName]); i:=ElementNames.Count-1; while (i>=0) do begin @@ -2493,9 +2515,10 @@ begin end; // find inherited node - if (CTNode.Desc=ctnProperty) - or ((CTNode.Desc in [ctnProcedure,ctnProcedureHead]) - and (CTTool.ProcNodeHasSpecifier(CTNode,psOVERRIDE))) + if (CTNode<>nil) and ( + (CTNode.Desc=ctnProperty) or + ((CTNode.Desc in [ctnProcedure,ctnProcedureHead]) + and (CTTool.ProcNodeHasSpecifier(CTNode,psOVERRIDE)))) then begin {$ifdef VerboseCodeHelp} debugln(['TCodeHelpManager.GetHTMLHintForNode: searching for inherited of ',CTNode.DescAsString,' ',dbgs(XYPos)]); @@ -2560,6 +2583,19 @@ begin {$endif} end; +function TCodeHelpManager.GetHTMLHintForNode(CTTool: TFindDeclarationTool; + CTNode: TCodeTreeNode; XYPos: TCodeXYPosition; Options: TCodeHelpHintOptions; + out BaseURL, HTMLHint: string; out CacheWasUsed: boolean + ): TCodeHelpParseResult; +var + ExprType: TExpressionType; +begin + ExprType.Desc:=xtContext; + ExprType.Context.Tool:=CTTool; + ExprType.Context.Node:=CTNode; + Result := GetHTMLHintForExpr(ExprType, XYPos, Options, BaseURL, HTMLHint, CacheWasUsed); +end; + function TCodeHelpManager.GetHTMLHintForUnit(AUnitName, InFilename: string; BaseDir: string; Options: TCodeHelpHintOptions; out BaseURL, HTMLHint: string; out CacheWasUsed: boolean): TCodeHelpParseResult; @@ -2615,23 +2651,37 @@ begin end; function TCodeHelpManager.GetHTMLDeclarationHeader(Tool: TFindDeclarationTool; - Node: TCodeTreeNode; XYPos: TCodeXYPosition): string; + Node: TCodeTreeNode; Desc: TExpressionTypeDesc; XYPos: TCodeXYPosition + ): string; var CTHint: String; begin Result:='
'; // add declaration - CTHint:=Tool.GetSmartHint(Node,XYPos,false); + if Desc=xtContext then + CTHint:=Tool.GetSmartHint(Node,XYPos,false) + else if Desc in xtAllPredefinedTypes then + CTHint:='type '+ExpressionTypeDescNames[Desc]; Result:=Result+' '+SourceToFPDocHint(CTHint)+''; // add link to declaration Result:=Result+'
'+LineEnding; - if XYPos.Code=nil then - Tool.CleanPosToCaret(Node.StartPos,XYPos); + if XYPos.Code=nil then begin + if (Node<>nil) then + Tool.CleanPosToCaret(Node.StartPos,XYPos) + else if Desc in xtAllPredefinedTypes then + Tool.CleanPosToCaret(Tool.Tree.Root.StartPos,XYPos); + end; Result:=Result+' '+SourcePosToFPDocHint(XYPos)+LineEnding; Result:=Result+'
'+LineEnding; end; +function TCodeHelpManager.GetHTMLDeclarationHeader(Tool: TFindDeclarationTool; + Node: TCodeTreeNode; XYPos: TCodeXYPosition): string; +begin + Result := GetHTMLDeclarationHeader(Tool, Node, xtContext, XYPos); +end; + function TCodeHelpManager.GetPasDocCommentsAsHTML(Tool: TFindDeclarationTool; Node: TCodeTreeNode): string; var diff --git a/ide/sourceeditprocs.pas b/ide/sourceeditprocs.pas index 621a879aab..53ee229748 100644 --- a/ide/sourceeditprocs.pas +++ b/ide/sourceeditprocs.pas @@ -238,6 +238,7 @@ var ImageIndex: longint; HintModifiers: TPascalHintModifiers; HintModifier: TPascalHintModifier; + HelperForNode: TCodeTreeNode; begin ForegroundColor := ColorToRGB(ACanvas.Font.Color); Result.X := 0; @@ -421,10 +422,14 @@ begin case ANode.Desc of ctnClass,ctnObject,ctnObjCClass,ctnObjCCategory, ctnCPPClass, - ctnClassInterface,ctnObjCProtocol,ctnDispinterface: + ctnClassInterface,ctnObjCProtocol,ctnDispinterface, + ctnClassHelper,ctnRecordHelper,ctnTypeHelper: begin case ANode.Desc of ctnClass: s:=s+'class'; + ctnClassHelper: s:=s+'class helper'; + ctnRecordHelper: s:=s+'record helper'; + ctnTypeHelper: s:=s+'type helper'; ctnObject: s:=s+'object'; ctnObjCClass: s:=s+'objcclass'; ctnObjCCategory: s:=s+'objccategory'; @@ -438,9 +443,15 @@ begin except on ECodeToolError do ; end; + if ANode.Desc in [ctnClassHelper, ctnRecordHelper, ctnTypeHelper] then + HelperForNode := IdentItem.Tool.FindHelperForNode(ANode) + else + HelperForNode := nil; SubNode:=IdentItem.Tool.FindInheritanceNode(ANode); if SubNode<>nil then s:=s+IdentItem.Tool.ExtractNode(SubNode,[]); + if HelperForNode<>nil then + s:=s+' '+IdentItem.Tool.ExtractNode(HelperForNode,[]); end; ctnRecordType: s:=s+'record'; diff --git a/images/laz_images_list.txt b/images/laz_images_list.txt index d944fd2181..08b00f1015 100644 --- a/images/laz_images_list.txt +++ b/images/laz_images_list.txt @@ -140,6 +140,9 @@ states/state_unit_circular_reference.png states/state_unknown.png states/state_warning.png codeexplorer/ce_class.png +codeexplorer/ce_classinterface.png +codeexplorer/ce_record.png +codeexplorer/ce_helper.png codeexplorer/ce_const.png codeexplorer/ce_default.png codeexplorer/ce_deprecated.png