IDE, CodeTools: support for unit names with dots. Issue #22235

git-svn-id: trunk@50266 -
This commit is contained in:
ondrej 2015-11-09 22:23:19 +00:00
parent 7395b9b047
commit d49143fd83
7 changed files with 383 additions and 58 deletions

View File

@ -41,7 +41,7 @@ interface
uses uses
Classes, SysUtils, AVL_Tree, SourceLog, KeywordFuncLists, FileProcs, Classes, SysUtils, AVL_Tree, SourceLog, KeywordFuncLists, FileProcs,
LazFileUtils, LazUTF8; LazFileUtils, LazUTF8, strutils;
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
{ These functions are used by the codetools } { These functions are used by the codetools }
@ -225,22 +225,49 @@ type
private private
FFilename: string; FFilename: string;
FUnitName: string; FUnitName: string;
function GetFileUnitNameWithoutNamespace: string;
function GetIdentifierStartInUnitName: Integer;
public public
constructor Create(const TheUnitName, TheFilename: string); constructor Create(const TheUnitName, TheFilename: string);
property FileUnitName: string read FUnitName; property FileUnitName: string read FUnitName;
property FileUnitNameWithoutNamespace: string read GetFileUnitNameWithoutNamespace;
property Filename: string read FFilename; property Filename: string read FFilename;
property IdentifierStartInUnitName: Integer read GetIdentifierStartInUnitName;
end; end;
TNameSpaceInfo = class
private
FFilename: string;
FNamespace: string;
FIdentifierStartInUnitName: Integer;
public
constructor Create(const TheNamespace, TheFilename: string; TheIdentifierStartInUnitName: Integer);
property Filename: string read FFilename;
property Namespace: string read FNamespace;
property IdentifierStartInUnitName: Integer read FIdentifierStartInUnitName;
end;
procedure AddToTreeOfUnitFilesOrNamespaces(
var TreeOfUnitFiles, TreeOfNameSpaces: TAVLTree;
const NameSpacePath, Filename: string;
CaseInsensitive, KeepDoubles: boolean);
function GatherUnitFiles(const BaseDir, SearchPath, function GatherUnitFiles(const BaseDir, SearchPath,
Extensions: string; KeepDoubles, CaseInsensitive: boolean; Extensions, NameSpacePath: string; KeepDoubles, CaseInsensitive: boolean;
var TreeOfUnitFiles: TAVLTree): boolean; var TreeOfUnitFiles, TreeOfNamespaces: TAVLTree): boolean;
procedure FreeTreeOfUnitFiles(TreeOfUnitFiles: TAVLTree); procedure FreeTreeOfUnitFiles(TreeOfUnitFiles: TAVLTree);
procedure AddToTreeOfUnitFiles(var TreeOfUnitFiles: TAVLTree; procedure AddToTreeOfUnitFiles(var TreeOfUnitFiles: TAVLTree;
const Filename: string; const Filename, Unitname: string;
KeepDoubles: boolean);
procedure AddToTreeOfNamespaces(var TreeOfNameSpaces: TAVLTree;
const FileName, UnitName, ParentNameSpacePath: string;
KeepDoubles: boolean); KeepDoubles: boolean);
function CompareUnitFileInfos(Data1, Data2: Pointer): integer; function CompareUnitFileInfos(Data1, Data2: Pointer): integer;
function CompareNameSpaceInfos(Data1, Data2: Pointer): integer;
function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString, function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString,
UnitFileInfo: Pointer): integer; UnitFileInfo: Pointer): integer;
function CompareNameSpaceAndNameSpaceInfo(NamespacePAnsiString,
NamespaceInfo: Pointer): integer;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// functions / procedures // functions / procedures
@ -5636,15 +5663,61 @@ begin
System.Move(p^,Result[1],l); System.Move(p^,Result[1],l);
end; end;
function GatherUnitFiles(const BaseDir, SearchPath, procedure AddToTreeOfUnitFilesOrNamespaces(var TreeOfUnitFiles,
Extensions: string; KeepDoubles, CaseInsensitive: boolean; TreeOfNameSpaces: TAVLTree; const NameSpacePath, Filename: string;
var TreeOfUnitFiles: TAVLTree): boolean; CaseInsensitive, KeepDoubles: boolean);
procedure FileAndNameSpaceFits(const UnitName: string; out FileNameFits, NameSpaceFits: Boolean);
var
CompareCaseInsensitive: Boolean;
begin
FileNameFits := False;
NameSpaceFits := False;
if NameSpacePath = '' then begin
//we search for files without namespace path
FileNameFits := pos('.', UnitName) = 0;
NameSpaceFits := not FileNameFits;
Exit;
end;
if Length(UnitName) < Length(NameSpacePath) then Exit;
CompareCaseInsensitive:=CaseInsensitive;
{$IFDEF Windows}
CompareCaseInsensitive:=true;
{$ENDIF}
if CompareText(PChar(UnitName), Length(NameSpacePath), PChar(NameSpacePath), Length(NameSpacePath), not CompareCaseInsensitive) = 0 then
begin
FileNameFits := PosEx('.', UnitName, Length(NameSpacePath)+1) = 0;
NameSpaceFits := not FileNameFits;
end;
end;
var
FileNameFits, NameSpaceFits: Boolean;
UnitName: string;
begin
UnitName := ExtractFileNameOnly(Filename);
FileAndNameSpaceFits(UnitName, FileNameFits, NameSpaceFits);
if FileNameFits then
AddToTreeOfUnitFiles(TreeOfUnitFiles,FileName,UnitName,
KeepDoubles);
if NameSpaceFits then
AddToTreeOfNamespaces(TreeOfNamespaces,FileName,UnitName,NameSpacePath,
KeepDoubles)
end;
function GatherUnitFiles(const BaseDir, SearchPath, Extensions,
NameSpacePath: string; KeepDoubles, CaseInsensitive: boolean;
var TreeOfUnitFiles, TreeOfNamespaces: TAVLTree): boolean;
// BaseDir: base directory, used when SearchPath is relative // BaseDir: base directory, used when SearchPath is relative
// SearchPath: semicolon separated list of directories // SearchPath: semicolon separated list of directories
// Extensions: semicolon separated list of extensions (e.g. 'pas;.pp;ppu') // Extensions: semicolon separated list of extensions (e.g. 'pas;.pp;ppu')
// NameSpacePath: gather files only from this namespace path
// KeepDoubles: false to return only the first match of each unit // KeepDoubles: false to return only the first match of each unit
// CaseInsensitive: true to ignore case on comparing extensions // CaseInsensitive: true to ignore case on comparing extensions
// TreeOfUnitFiles: tree of TUnitFileInfo // TreeOfUnitFiles: tree of TUnitFileInfo
// TreeOfNamespaces: tree of TNameSpaceInfo
var var
SearchedDirectories: TAVLTree; // tree of AnsiString SearchedDirectories: TAVLTree; // tree of AnsiString
@ -5760,8 +5833,8 @@ var
then then
continue; continue;
if ExtensionFits(FileInfo.Name) then begin if ExtensionFits(FileInfo.Name) then begin
AddToTreeOfUnitFiles(TreeOfUnitFiles,ADirectory+FileInfo.Name, AddToTreeOfUnitFilesOrNamespaces(TreeOfUnitFiles, TreeOfNamespaces,
KeepDoubles); NameSpacePath, ADirectory+FileInfo.Name, CaseInsensitive, KeepDoubles);
end; end;
until FindNextUTF8(FileInfo)<>0; until FindNextUTF8(FileInfo)<>0;
end; end;
@ -5808,16 +5881,14 @@ begin
TreeOfUnitFiles.Free; TreeOfUnitFiles.Free;
end; end;
procedure AddToTreeOfUnitFiles(var TreeOfUnitFiles: TAVLTree; procedure AddToTreeOfUnitFiles(var TreeOfUnitFiles: TAVLTree; const Filename,
const Filename: string; KeepDoubles: boolean); Unitname: string; KeepDoubles: boolean);
var var
AnUnitName: String;
NewItem: TUnitFileInfo; NewItem: TUnitFileInfo;
begin begin
AnUnitName:=ExtractFileNameOnly(Filename);
if (not KeepDoubles) then begin if (not KeepDoubles) then begin
if (TreeOfUnitFiles<>nil) if (TreeOfUnitFiles<>nil)
and (TreeOfUnitFiles.FindKey(Pointer(AnUnitName), and (TreeOfUnitFiles.FindKey(Pointer(UnitName),
@CompareUnitNameAndUnitFileInfo)<>nil) @CompareUnitNameAndUnitFileInfo)<>nil)
then begin then begin
// an unit with the same name was already found and doubles are not // an unit with the same name was already found and doubles are not
@ -5828,21 +5899,64 @@ begin
// add // add
if TreeOfUnitFiles=nil then if TreeOfUnitFiles=nil then
TreeOfUnitFiles:=TAVLTree.Create(@CompareUnitFileInfos); TreeOfUnitFiles:=TAVLTree.Create(@CompareUnitFileInfos);
NewItem:=TUnitFileInfo.Create(AnUnitName,Filename); NewItem:=TUnitFileInfo.Create(UnitName,Filename);
TreeOfUnitFiles.Add(NewItem); TreeOfUnitFiles.Add(NewItem);
end; end;
procedure AddToTreeOfNamespaces(var TreeOfNameSpaces: TAVLTree; const FileName,
UnitName, ParentNameSpacePath: string; KeepDoubles: boolean);
var
AnNameSpace: String;
NewItem: TNameSpaceInfo;
PointPos: Integer;
begin
PointPos := PosEx('.', UnitName, Length(ParentNameSpacePath)+1);
if PointPos = 0 then Exit;
AnNameSpace:=Copy(UnitName, Length(ParentNameSpacePath)+1, PointPos - Length(ParentNameSpacePath) - 1);
if AnNameSpace = '' then Exit;
if (not KeepDoubles) then begin
if (TreeOfNameSpaces<>nil)
and (TreeOfNameSpaces.FindKey(Pointer(AnNameSpace),
@CompareNameSpaceAndNameSpaceInfo)<>nil)
then begin
// a namespace with the same name was already found and doubles are not
// wanted
exit;
end;
end;
// add
if TreeOfNameSpaces=nil then
TreeOfNameSpaces:=TAVLTree.Create(@CompareNameSpaceInfos);
NewItem:=TNameSpaceInfo.Create(AnNameSpace,FileName,Length(ParentNameSpacePath)+1);
TreeOfNameSpaces.Add(NewItem);
end;
function CompareUnitFileInfos(Data1, Data2: Pointer): integer; function CompareUnitFileInfos(Data1, Data2: Pointer): integer;
begin begin
Result:=CompareIdentifiers(PChar(TUnitFileInfo(Data1).FileUnitName), Result:=CompareIdentifiers(PChar(TUnitFileInfo(Data1).FileUnitName),
PChar(TUnitFileInfo(Data2).FileUnitName)); PChar(TUnitFileInfo(Data2).FileUnitName));
end; end;
function CompareNameSpaceInfos(Data1, Data2: Pointer): integer;
begin
Result:=CompareIdentifiers(PChar(TNameSpaceInfo(Data1).NameSpace),
PChar(TNameSpaceInfo(Data2).NameSpace));
end;
function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString, function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString,
UnitFileInfo: Pointer): integer; UnitFileInfo: Pointer): integer;
begin begin
Result:=CompareIdentifiers(PChar(UnitnamePAnsiString), //do not use CompareIdentifiers - they compare only to the first "."
PChar(TUnitFileInfo(UnitFileInfo).FileUnitName)); Result:=CompareText(PChar(UnitnamePAnsiString),
PChar(TUnitFileInfo(UnitFileInfo).FileUnitName));
end;
function CompareNameSpaceAndNameSpaceInfo(NamespacePAnsiString,
NamespaceInfo: Pointer): integer;
begin
//do not use CompareIdentifiers - they compare only to the first "."
Result:=CompareText(PChar(NamespacePAnsiString),
PChar(TNameSpaceInfo(NamespaceInfo).NameSpace));
end; end;
function CountNeededLineEndsToAddForward(const Src: string; function CountNeededLineEndsToAddForward(const Src: string;
@ -5973,6 +6087,16 @@ begin
Result:=CompareText(Txt1,Len1,Txt2,Len2,CaseSensitive); Result:=CompareText(Txt1,Len1,Txt2,Len2,CaseSensitive);
end; end;
{ TNameSpaceInfo }
constructor TNameSpaceInfo.Create(const TheNamespace, TheFilename: string;
TheIdentifierStartInUnitName: Integer);
begin
FNamespace:=TheNamespace;
FFilename:=TheFilename;
FIdentifierStartInUnitName:=TheIdentifierStartInUnitName;
end;
{ TUnitFileInfo } { TUnitFileInfo }
constructor TUnitFileInfo.Create(const TheUnitName, TheFilename: string); constructor TUnitFileInfo.Create(const TheUnitName, TheFilename: string);
@ -5981,6 +6105,27 @@ begin
FFilename:=TheFilename; FFilename:=TheFilename;
end; end;
function TUnitFileInfo.GetFileUnitNameWithoutNamespace: string;
var
LastPoint: Integer;
begin
LastPoint := LastDelimiter('.', FUnitName);
if LastPoint > 0 then
Result := Copy(FUnitName, LastPoint+1, High(Integer))
else
Result := FUnitName;
end;
function TUnitFileInfo.GetIdentifierStartInUnitName: Integer;
var
LastPoint: Integer;
begin
LastPoint := LastDelimiter('.', FUnitName);
if LastPoint > 0 then
Result := LastPoint+1
else
Result := 1;
end;
//============================================================================= //=============================================================================

View File

@ -80,8 +80,10 @@ const
ctnVarDefinition = 21; ctnVarDefinition = 21;
ctnConstDefinition = 22; ctnConstDefinition = 22;
ctnGlobalProperty = 23; ctnGlobalProperty = 23;
ctnUseUnit = 24; // StartPos=unitname, EndPos=unitname+inFilename ctnUseUnit = 24; // StartPos=unit, EndPos=unitname+inFilename, children ctnUseUnitNamespace, ctnUseUnitClearName
ctnVarArgs = 25; ctnVarArgs = 25;
ctnUseUnitNamespace = 26; // <namespace>.clearname.pas
ctnUseUnitClearName = 27; // namespace.<clearname>.pas
ctnClass = 30; ctnClass = 30;
ctnClassInterface = 31; ctnClassInterface = 31;
@ -194,7 +196,7 @@ const
ctnInitialization,ctnFinalization]; ctnInitialization,ctnFinalization];
AllFindContextDescs = AllIdentifierDefinitions + AllCodeSections + AllClasses + AllFindContextDescs = AllIdentifierDefinitions + AllCodeSections + AllClasses +
[ctnProcedure]; [ctnProcedure];
AllPointContexts = AllClasses+AllSourceTypes+[ctnEnumerationType,ctnInterface,ctnImplementation,ctnTypeType]; AllPointContexts = AllClasses+AllSourceTypes+[ctnEnumerationType,ctnInterface,ctnImplementation,ctnTypeType,ctnUseUnitNamespace,ctnUseUnitClearName];
// CodeTreeNodeSubDescriptors // CodeTreeNodeSubDescriptors
@ -397,6 +399,8 @@ begin
ctnPackage: Result:='Package'; ctnPackage: Result:='Package';
ctnLibrary: Result:='Library'; ctnLibrary: Result:='Library';
ctnUnit: Result:='Unit'; ctnUnit: Result:='Unit';
ctnUseUnitNamespace: Result:='Namespace';
ctnUseUnitClearName: Result:='Unit name without namespace';
ctnInterface: Result:='Interface Section'; ctnInterface: Result:='Interface Section';
ctnImplementation: Result:='Implementation'; ctnImplementation: Result:='Implementation';
ctnInitialization: Result:='Initialization'; ctnInitialization: Result:='Initialization';

View File

@ -2191,7 +2191,16 @@ begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsString(CursorNode.Desc),' HasChildren=',dbgs(CursorNode.FirstChild<>nil)); DebugLn('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsString(CursorNode.Desc),' HasChildren=',dbgs(CursorNode.FirstChild<>nil));
{$ENDIF} {$ENDIF}
if (CursorNode.Desc in [ctnUsesSection,ctnUseUnit]) then begin if (CursorNode.Desc = ctnUseUnitNamespace) then begin
NewExprType.Desc:=xtContext;
NewExprType.Context.Node:=CursorNode;
NewExprType.Context.Tool:=Self;
CleanPosToCaret(CursorNode.StartPos, NewPos);
NewTopLine := NewPos.Y;
Result := True;
Exit;
end else
if (CursorNode.Desc in [ctnUsesSection,ctnUseUnitClearName]) then begin
// in uses section // in uses section
//DebugLn(['TFindDeclarationTool.FindDeclaration IsUsesSection']); //DebugLn(['TFindDeclarationTool.FindDeclaration IsUsesSection']);
Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos, Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos,
@ -2751,7 +2760,10 @@ begin
ReadNextAtom; ReadNextAtom;
if not UpAtomIs('USES') then if not UpAtomIs('USES') then
RaiseUsesExpected; RaiseUsesExpected;
end; end else
if (UsesNode.Desc = ctnUseUnitClearName) then
MoveCursorToNodeStart(UsesNode.Parent);
repeat repeat
ReadNextAtom; // read name ReadNextAtom; // read name
if CurPos.StartPos>CleanPos then break; if CurPos.StartPos>CleanPos then break;
@ -3261,11 +3273,20 @@ begin
end; end;
end; end;
ctnUseUnit: ctnUseUnitNamespace:
begin
// hint for unit namespace in "uses" section
Result += 'namespace ';
MoveCursorToNodeStart(Node);
ReadNextAtom;
Result := Result + GetAtom;
end;
ctnUseUnitClearName:
begin begin
// hint for unit in "uses" section // hint for unit in "uses" section
Result += 'unit '; Result += 'unit ';
MoveCursorToNodeStart(Node); MoveCursorToNodeStart(Node.Parent);
Result := Result + ReadIdentifierWithDots; Result := Result + ReadIdentifierWithDots;
end end
@ -3974,6 +3995,55 @@ var
//debugln(['SearchInHelpers END']); //debugln(['SearchInHelpers END']);
end; end;
function SearchInNamespaces(UsesNode, SourceNamespaceNode: TCodeTreeNode): Boolean;
var
UnitNode, ThisNamespaceNode, TargetNamespaceNode: TCodeTreeNode;
Match: Boolean;
begin
Result := False;
if UsesNode=nil then Exit;
UnitNode := UsesNode.LastChild;
while UnitNode<>nil do
begin
ThisNamespaceNode := SourceNamespaceNode.Parent.FirstChild;
TargetNamespaceNode := UnitNode.FirstChild;
Match := False;
while (ThisNamespaceNode<>nil) and (TargetNamespaceNode<>nil) do
begin
if CompareIdentifiers(
@Src[ThisNamespaceNode.StartPos],
@Src[TargetNamespaceNode.StartPos]) <> 0
then Break;
if (ThisNamespaceNode=SourceNamespaceNode) then
begin
Match := True;
Break;
end;
ThisNamespaceNode := ThisNamespaceNode.NextBrother;
TargetNamespaceNode := TargetNamespaceNode.NextBrother;
end;
if Match then
begin
//namespace paths match
if (TargetNamespaceNode.NextBrother<>nil)
and (
(Params.Identifier=nil) or
CompareSrcIdentifiers(TargetNamespaceNode.NextBrother.StartPos,Params.Identifier))
then begin
Params.SetResult(Self,TargetNamespaceNode.NextBrother);
Result:=CheckResult(true,true);
if not (fdfCollect in Flags) then
exit;
end;
end;
UnitNode := UnitNode.PriorBrother;
end;
end;
function SearchNextNode: boolean; function SearchNextNode: boolean;
const const
AbortNoCacheResult = false; AbortNoCacheResult = false;
@ -4212,6 +4282,14 @@ begin
exit; exit;
end; end;
if (ContextNode.Desc=ctnUseUnitNamespace) then
begin
//search in namespaces
if SearchInNamespaces(FindMainUsesNode, Params.ContextNode) then exit;
if SearchInNamespaces(FindImplementationUsesNode, Params.ContextNode) then exit;
Exit;
end;
// find class helper functions // find class helper functions
SearchInHelpersInTheEnd := False; SearchInHelpersInTheEnd := False;
if (fdfSearchInHelpers in Flags) if (fdfSearchInHelpers in Flags)
@ -6127,6 +6205,8 @@ begin
ListOfPCodeXYPosition:=nil; ListOfPCodeXYPosition:=nil;
BuildTreeAndGetCleanPos(CursorPos,CleanPos); BuildTreeAndGetCleanPos(CursorPos,CleanPos);
Node:=FindDeepestNodeAtPos(CleanPos,true); Node:=FindDeepestNodeAtPos(CleanPos,true);
if Node.Desc in [ctnUseUnitNamespace,ctnUseUnitClearName] then
Node:=Node.Parent;
if Node.Desc<>ctnUseUnit then if Node.Desc<>ctnUseUnit then
RaiseException('This function needs the cursor at a unit in a uses clause'); RaiseException('This function needs the cursor at a unit in a uses clause');
// cursor is on an used unit -> try to locate it // cursor is on an used unit -> try to locate it
@ -7333,19 +7413,20 @@ begin
Node:=UsesNode.LastChild; Node:=UsesNode.LastChild;
while Node<>nil do begin while Node<>nil do begin
if (fdfCollect in Params.Flags) then begin if (fdfCollect in Params.Flags) then begin
CollectResult:=DoOnIdentifierFound(Params,Node); CollectResult:=DoOnIdentifierFound(Params,Node.FirstChild);
if CollectResult=ifrAbortSearch then begin if CollectResult=ifrAbortSearch then begin
Result:=false; Result:=false;
exit; exit;
end else if CollectResult=ifrSuccess then begin end else if CollectResult=ifrSuccess then begin
Result:=true; Result:=true;
Params.SetResult(Self,Node); Params.SetResult(Self,Node.FirstChild);
exit; exit;
end; end;
end else if CompareSrcIdentifiers(Node.StartPos,Params.Identifier) then begin end else if CompareSrcIdentifiers(Node.StartPos,Params.Identifier) then begin
// the searched identifier was a uses AUnitName, point to the identifier in // the searched identifier was a uses AUnitName, point to the identifier in
// the uses section // the uses section
Params.SetResult(Self,Node,Node.StartPos); // if the unit name has a namespace defined point to the namespace
Params.SetResult(Self,Node.FirstChild);
Result:=true; Result:=true;
exit; exit;
end; end;
@ -8525,7 +8606,7 @@ var
{$IFDEF ShowExprEval} {$IFDEF ShowExprEval}
debugln([' FindExpressionTypeOfTerm ResolveUseUnit used unit -> interface node ',dbgstr(ExprType.Context.Tool.ExtractNode(ExprType.Context.Node,[]))]); debugln([' FindExpressionTypeOfTerm ResolveUseUnit used unit -> interface node ',dbgstr(ExprType.Context.Tool.ExtractNode(ExprType.Context.Node,[]))]);
{$ENDIF} {$ENDIF}
AnUnitName:=aTool.ExtractUsedUnitName(ExprType.Context.Node,@InFilename); AnUnitName:=aTool.ExtractUsedUnitName(ExprType.Context.Node.Parent,@InFilename);
NewCodeTool:=aTool.FindCodeToolForUsedUnit(AnUnitName,InFilename,true); NewCodeTool:=aTool.FindCodeToolForUsedUnit(AnUnitName,InFilename,true);
NewCodeTool.BuildInterfaceIdentifierCache(true); NewCodeTool.BuildInterfaceIdentifierCache(true);
NewNode:=NewCodeTool.FindInterfaceNode; NewNode:=NewCodeTool.FindInterfaceNode;
@ -8568,7 +8649,7 @@ var
ExprType.Context.Node:=ExprType.Context.Tool.GetInterfaceNode; ExprType.Context.Node:=ExprType.Context.Tool.GetInterfaceNode;
end; end;
end end
else if (ExprType.Context.Node.Desc=ctnUseUnit) then begin else if (ExprType.Context.Node.Desc=ctnUseUnitClearName) then begin
// uses unit name => interface of used unit // uses unit name => interface of used unit
ResolveUseUnit; ResolveUseUnit;
end end

View File

@ -169,13 +169,20 @@ type
function GetNodeHash(ANode: TCodeTreeNode): string; function GetNodeHash(ANode: TCodeTreeNode): string;
function CompareParamList(CompareItem: TIdentifierListItem): integer; function CompareParamList(CompareItem: TIdentifierListItem): integer;
function CompareParamList(CompareItem: TIdentifierListSearchItem): integer; function CompareParamList(CompareItem: TIdentifierListSearchItem): integer;
function CalcMemSize: PtrUInt; function CalcMemSize: PtrUInt; virtual;
public public
property ParamTypeList: string read GetParamTypeList write SetParamTypeList; property ParamTypeList: string read GetParamTypeList write SetParamTypeList;
property ParamNameList: string read GetParamNameList write SetParamNameList; property ParamNameList: string read GetParamNameList write SetParamNameList;
property ResultType: string read FResultType write SetResultType; property ResultType: string read FResultType write SetResultType;
property Node: TCodeTreeNode read GetNode write SetNode; property Node: TCodeTreeNode read GetNode write SetNode;
end; end;
TUnitNameSpaceIdentifierListItem = class(TIdentifierListItem)
public
UnitFileName: string;
IdentifierStartInUnitName: Integer;
function CalcMemSize: PtrUInt; override;
end;
TIdentifierListFlag = ( TIdentifierListFlag = (
ilfFilteredListNeedsUpdate, ilfFilteredListNeedsUpdate,
@ -360,6 +367,9 @@ type
// property names in source) // property names in source)
FIDTFoundMethods: TAVLTree;// tree of TCodeTreeNodeExtension Txt=clean text FIDTFoundMethods: TAVLTree;// tree of TCodeTreeNodeExtension Txt=clean text
FIDTTreeOfUnitFiles: TAVLTree;// tree of TUnitFileInfo FIDTTreeOfUnitFiles: TAVLTree;// tree of TUnitFileInfo
FIDTTreeOfUnitFiles_NamespacePath: string;
FIDTTreeOfUnitFiles_CaseInsensitive: Boolean;
FIDTTreeOfNamespaces: TAVLTree;// tree of TNameSpaceInfo
procedure AddToTreeOfUnitFileInfo(const AFilename: string); procedure AddToTreeOfUnitFileInfo(const AFilename: string);
procedure AddBaseConstant(const BaseName: PChar); procedure AddBaseConstant(const BaseName: PChar);
procedure AddBaseType(const BaseName: PChar); procedure AddBaseType(const BaseName: PChar);
@ -376,7 +386,7 @@ type
const Context, GatherContext: TFindContext); const Context, GatherContext: TFindContext);
procedure GatherUsefulIdentifiers(CleanPos: integer; procedure GatherUsefulIdentifiers(CleanPos: integer;
const Context, GatherContext: TFindContext); const Context, GatherContext: TFindContext);
procedure GatherUnitnames; procedure GatherUnitnames(const NameSpacePath: string = '');
procedure GatherSourceNames(const Context: TFindContext); procedure GatherSourceNames(const Context: TFindContext);
procedure GatherContextKeywords(const Context: TFindContext; procedure GatherContextKeywords(const Context: TFindContext;
CleanPos: integer; BeautifyCodeOptions: TBeautifyCodeOptions); CleanPos: integer; BeautifyCodeOptions: TBeautifyCodeOptions);
@ -503,6 +513,14 @@ begin
Result:='['+Result+']'; Result:='['+Result+']';
end; end;
{ TUnitNameSpaceIdentifierListItem }
function TUnitNameSpaceIdentifierListItem.CalcMemSize: PtrUInt;
begin
Result := inherited CalcMemSize
+MemSizeString(UnitFileName);
end;
{ TIdentifierList } { TIdentifierList }
function TIdentifierList.CompareIdentListItems(Tree: TAvgLvlTree; Data1, function TIdentifierList.CompareIdentListItems(Tree: TAvgLvlTree; Data1,
@ -905,7 +923,8 @@ end;
procedure TIdentCompletionTool.AddToTreeOfUnitFileInfo(const AFilename: string); procedure TIdentCompletionTool.AddToTreeOfUnitFileInfo(const AFilename: string);
begin begin
AddToTreeOfUnitFiles(FIDTTreeOfUnitFiles,AFilename,false); AddToTreeOfUnitFilesOrNamespaces(FIDTTreeOfUnitFiles,FIDTTreeOfNamespaces,
FIDTTreeOfUnitFiles_NamespacePath,AFilename,FIDTTreeOfUnitFiles_CaseInsensitive,false);
end; end;
procedure TIdentCompletionTool.AddCompilerProcedure(const AProcName, AParameterList: PChar); procedure TIdentCompletionTool.AddCompilerProcedure(const AProcName, AParameterList: PChar);
@ -1225,7 +1244,7 @@ begin
ctnRecordCase: ctnRecordCase:
Ident:=@FoundContext.Tool.Src[Params.NewCleanPos]; Ident:=@FoundContext.Tool.Src[Params.NewCleanPos];
ctnUseUnit: ctnUseUnitNamespace,ctnUseUnitClearName:
if (FoundContext.Tool=Self) then begin if (FoundContext.Tool=Self) then begin
Ident:=@Src[FoundContext.Node.StartPos]; Ident:=@Src[FoundContext.Node.StartPos];
end; end;
@ -1295,7 +1314,7 @@ procedure TIdentCompletionTool.GatherPredefinedIdentifiers(CleanPos: integer;
CompilerFuncLevel, CompilerFuncLevel,
nil, nil,
nil, nil,
ctnUseUnit); ctnUseUnitClearName);
CurrentIdentifierList.Add(NewItem); CurrentIdentifierList.Add(NewItem);
end; end;
@ -1486,7 +1505,7 @@ begin
end; end;
end; end;
procedure TIdentCompletionTool.GatherUnitnames; procedure TIdentCompletionTool.GatherUnitnames(const NameSpacePath: string);
procedure GatherUnitsFromSet; procedure GatherUnitsFromSet;
begin begin
@ -1499,10 +1518,11 @@ var
BaseDir: String; BaseDir: String;
ANode: TAVLTreeNode; ANode: TAVLTreeNode;
UnitFileInfo: TUnitFileInfo; UnitFileInfo: TUnitFileInfo;
NewItem: TIdentifierListItem; NewItem: TUnitNameSpaceIdentifierListItem;
UnitExt: String; UnitExt: String;
SrcExt: String; SrcExt: String;
CurSourceName: String; CurSourceName: String;
NameSpaceInfo: TNameSpaceInfo;
begin begin
UnitPath:=''; UnitPath:='';
SrcPath:=''; SrcPath:='';
@ -1510,37 +1530,64 @@ begin
//DebugLn('TIdentCompletionTool.GatherUnitnames UnitPath="',UnitPath,'" SrcPath="',SrcPath,'"'); //DebugLn('TIdentCompletionTool.GatherUnitnames UnitPath="',UnitPath,'" SrcPath="',SrcPath,'"');
BaseDir:=ExtractFilePath(MainFilename); BaseDir:=ExtractFilePath(MainFilename);
FIDTTreeOfUnitFiles:=nil; FIDTTreeOfUnitFiles:=nil;
FIDTTreeOfNamespaces:=nil;
try try
// search in unitpath // search in unitpath
FIDTTreeOfUnitFiles_CaseInsensitive := true;
FIDTTreeOfUnitFiles_NamespacePath := NameSpacePath;
UnitExt:='pp;pas;ppu'; UnitExt:='pp;pas;ppu';
if Scanner.CompilerMode=cmMacPas then if Scanner.CompilerMode=cmMacPas then
UnitExt:=UnitExt+';p'; UnitExt:=UnitExt+';p';
GatherUnitFiles(BaseDir,UnitPath,UnitExt,false,true,FIDTTreeOfUnitFiles); GatherUnitFiles(BaseDir,UnitPath,UnitExt,NameSpacePath,false,true,FIDTTreeOfUnitFiles, FIDTTreeOfNamespaces);
// search in srcpath // search in srcpath
SrcExt:='pp;pas'; SrcExt:='pp;pas';
if Scanner.CompilerMode=cmMacPas then if Scanner.CompilerMode=cmMacPas then
SrcExt:=SrcExt+';p'; SrcExt:=SrcExt+';p';
GatherUnitFiles(BaseDir,SrcPath,SrcExt,false,true,FIDTTreeOfUnitFiles); GatherUnitFiles(BaseDir,SrcPath,SrcExt,NameSpacePath,false,true,FIDTTreeOfUnitFiles, FIDTTreeOfNamespaces);
// add unitlinks // add unitlinks
GatherUnitsFromSet; GatherUnitsFromSet;
// create list // create list
CurSourceName:=GetSourceName; CurSourceName:=GetSourceName;
ANode:=FIDTTreeOfUnitFiles.FindLowest; if FIDTTreeOfUnitFiles<> nil then
while ANode<>nil do begin begin
UnitFileInfo:=TUnitFileInfo(ANode.Data); ANode:=FIDTTreeOfUnitFiles.FindLowest;
if CompareIdentifiers(PChar(Pointer(UnitFileInfo.FileUnitName)), while ANode<>nil do begin
PChar(Pointer(CurSourceName)))<>0 UnitFileInfo:=TUnitFileInfo(ANode.Data);
then begin if CompareText(PChar(Pointer(UnitFileInfo.FileUnitName)), Length(UnitFileInfo.FileUnitName),
NewItem:=TIdentifierListItem.Create( PChar(Pointer(CurSourceName)), Length(CurSourceName), False)<>0
icompCompatible,true,0, then begin
CurrentIdentifierList.CreateIdentifier(UnitFileInfo.FileUnitName), // oooooo
0,nil,nil,ctnUnit); NewItem:=TUnitNameSpaceIdentifierListItem.Create(
CurrentIdentifierList.Add(NewItem); icompCompatible,true,0,
CurrentIdentifierList.CreateIdentifier(UnitFileInfo.FileUnitNameWithoutNamespace),
0,nil,nil,ctnUnit);
NewItem.UnitFileName := UnitFileInfo.Filename;
NewItem.IdentifierStartInUnitName := UnitFileInfo.IdentifierStartInUnitName;
if NewItem.IdentifierStartInUnitName < 1 then
NewItem.IdentifierStartInUnitName := 1;
CurrentIdentifierList.Add(NewItem);
end;
ANode:=FIDTTreeOfUnitFiles.FindSuccessor(ANode);
end;
end;
if FIDTTreeOfNamespaces<>nil then
begin
ANode:=FIDTTreeOfNamespaces.FindLowest;
while ANode<>nil do begin
NameSpaceInfo:=TNameSpaceInfo(ANode.Data);
NewItem:=TUnitNameSpaceIdentifierListItem.Create(
icompCompatible,true,0,
CurrentIdentifierList.CreateIdentifier(NameSpaceInfo.NameSpace),
0,nil,nil,ctnUseUnitNamespace);
NewItem.UnitFileName := NameSpaceInfo.Filename;
NewItem.IdentifierStartInUnitName := NameSpaceInfo.IdentifierStartInUnitName;
CurrentIdentifierList.Add(NewItem);
ANode:=FIDTTreeOfNamespaces.FindSuccessor(ANode);
end; end;
ANode:=FIDTTreeOfUnitFiles.FindSuccessor(ANode);
end; end;
finally finally
FreeTreeOfUnitFiles(FIDTTreeOfUnitFiles); FreeTreeOfUnitFiles(FIDTTreeOfUnitFiles);
FreeTreeOfUnitFiles(FIDTTreeOfNamespaces);
end; end;
end; end;
@ -2490,6 +2537,7 @@ var
IdentStartXY: TCodeXYPosition; IdentStartXY: TCodeXYPosition;
InFrontOfDirective: Boolean; InFrontOfDirective: Boolean;
ExprType: TExpressionType; ExprType: TExpressionType;
IdentifierPath: string;
procedure CheckProcedureDeclarationContext; procedure CheckProcedureDeclarationContext;
var var
@ -2551,6 +2599,18 @@ begin
CurrentIdentifierList.StartAtom:=CurPos; CurrentIdentifierList.StartAtom:=CurPos;
end; end;
MoveCursorToCleanPos(IdentStartPos);
ReadPriorAtom;
IdentifierPath := '';
while CurPos.Flag = cafPoint do
begin
ReadPriorAtom;
if CurPos.Flag <> cafWord then
Break;
IdentifierPath := GetUpAtom + '.' + IdentifierPath;
ReadPriorAtom;
end;
// find context // find context
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers B', DebugLn('TIdentCompletionTool.GatherIdentifiers B',
@ -2560,8 +2620,8 @@ begin
{$ENDIF} {$ENDIF}
GatherContext:=CreateFindContext(Self,CursorNode); GatherContext:=CreateFindContext(Self,CursorNode);
CurrentIdentifierList.NewMemberVisibility:=GetClassVisibility(CursorNode); CurrentIdentifierList.NewMemberVisibility:=GetClassVisibility(CursorNode);
if CursorNode.Desc in [ctnUsesSection,ctnUseUnit] then begin if CursorNode.Desc in [ctnUsesSection,ctnUseUnit,ctnUseUnitNamespace,ctnUseUnitClearName] then begin
GatherUnitNames; GatherUnitNames(IdentifierPath);
MoveCursorToCleanPos(IdentEndPos); MoveCursorToCleanPos(IdentEndPos);
ReadNextAtom; ReadNextAtom;
if (CurPos.Flag=cafWord) and (not UpAtomIs('IN')) then begin if (CurPos.Flag=cafWord) and (not UpAtomIs('IN')) then begin

View File

@ -1993,6 +1993,7 @@ function TPascalParserTool.ReadUsesSection(ExceptionOnError: boolean): boolean;
} }
var var
IsUses: Boolean; IsUses: Boolean;
LastUnitNode: TCodeTreeNode;
begin begin
Result:=false; Result:=false;
IsUses:=CurNode.Desc=ctnUsesSection; IsUses:=CurNode.Desc=ctnUsesSection;
@ -2016,8 +2017,14 @@ begin
CurNode.Desc:=ctnUseUnit; CurNode.Desc:=ctnUseUnit;
repeat repeat
CurNode.EndPos:=CurPos.EndPos; CurNode.EndPos:=CurPos.EndPos;
CreateChildNode;
LastUnitNode := CurNode;
CurNode.Desc:=ctnUseUnitClearName;
CurNode.EndPos:=CurNode.Parent.EndPos;
EndChildNode;
ReadNextAtom; ReadNextAtom;
if CurPos.Flag<>cafPoint then break; if CurPos.Flag<>cafPoint then break;
LastUnitNode.Desc:=ctnUseUnitNamespace;
ReadNextAtom; ReadNextAtom;
AtomIsIdentifierSaveE; AtomIsIdentifierSaveE;
until false; until false;

View File

@ -933,6 +933,12 @@ begin
ShowNode:=false; ShowNode:=false;
end; end;
//don't show child nodes of ctnUseUnit
if (CodeNode.Desc=ctnUseUnit)
then begin
ShowChilds:=false;
end;
// don't show subs // don't show subs
if CodeNode.Desc in [ctnConstant,ctnIdentifier,ctnRangedArrayType, if CodeNode.Desc in [ctnConstant,ctnIdentifier,ctnRangedArrayType,
ctnOpenArrayType,ctnOfConstType,ctnRangeType,ctnTypeType,ctnFileType, ctnOpenArrayType,ctnOfConstType,ctnRangeType,ctnTypeType,ctnFileType,

View File

@ -322,12 +322,18 @@ begin
s:='label'; s:='label';
end; end;
ctnUnit, ctnUseUnit: ctnUnit, ctnUseUnitClearName:
begin begin
AColor:=clBlack; AColor:=clBlack;
s:='unit'; s:='unit';
end; end;
ctnUseUnitNamespace:
begin
AColor:=clBlack;
s:='namespace';
end;
ctnNone: ctnNone:
if iliKeyword in IdentItem.Flags then begin if iliKeyword in IdentItem.Flags then begin
AColor:=clBlack; AColor:=clBlack;
@ -544,13 +550,29 @@ function FindUnitName(IdentList: TIdentifierList;
IdentItem: TIdentifierListItem): string; IdentItem: TIdentifierListItem): string;
var var
CodeBuf: TCodeBuffer; CodeBuf: TCodeBuffer;
LastPointPos: Integer;
begin begin
Result:=IdentItem.Identifier; Result:=IdentItem.Identifier;
CodeBuf:=CodeToolBoss.FindUnitSource(IdentList.StartContextPos.Code,Result,''); if IdentItem is TUnitNameSpaceIdentifierListItem then
if CodeBuf=nil then exit; begin
Result:=CodeToolBoss.GetSourceName(CodeBuf,true); CodeBuf:=CodeToolBoss.FindFile(TUnitNameSpaceIdentifierListItem(IdentItem).UnitFileName);
if CodeBuf=nil then Exit;
Result:=CodeToolBoss.GetSourceName(CodeBuf,true);
Result:=Copy(CodeToolBoss.GetSourceName(CodeBuf,true), TUnitNameSpaceIdentifierListItem(IdentItem).IdentifierStartInUnitName, Length(IdentItem.Identifier));
end else
begin
CodeBuf:=CodeToolBoss.FindUnitSource(IdentList.StartContextPos.Code,Result,'');
if CodeBuf=nil then Exit;
Result:=CodeToolBoss.GetSourceName(CodeBuf,true);
end;
if Result='' then if Result='' then
Result:=IdentItem.Identifier; Result:=IdentItem.Identifier
else
begin
LastPointPos := LastDelimiter('.', Result);
if LastPointPos > 0 then
Result := Copy(Result, LastPointPos+1, High(Integer));
end;
end; end;
function GetIdentCompletionValue(aCompletion : TSynCompletion; function GetIdentCompletionValue(aCompletion : TSynCompletion;
@ -617,7 +639,7 @@ begin
IsReadOnly:=IdentItem.IsPropertyReadOnly; IsReadOnly:=IdentItem.IsPropertyReadOnly;
end; end;
ctnUnit, ctnPackage, ctnLibrary: ctnUnit, ctnPackage, ctnLibrary, ctnUseUnitNamespace:
ValueType:=icvUnitName; ValueType:=icvUnitName;
end; end;
@ -739,7 +761,7 @@ begin
end; end;
if CodeToolsOpts.IdentComplAddSemicolon and if CodeToolsOpts.IdentComplAddSemicolon and
(IdentItem.GetDesc=ctnUseUnit) and (AddChar<>'.') and (IdentItem.GetDesc in [ctnUseUnitNamespace,ctnUseUnitClearName]) and (AddChar<>'.') and
not IdentList.StartUpAtomBehindIs('.')//check if there is already a point not IdentList.StartUpAtomBehindIs('.')//check if there is already a point
then then
Result+='.'; Result+='.';