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
Classes, SysUtils, AVL_Tree, SourceLog, KeywordFuncLists, FileProcs,
LazFileUtils, LazUTF8;
LazFileUtils, LazUTF8, strutils;
//----------------------------------------------------------------------------
{ These functions are used by the codetools }
@ -225,22 +225,49 @@ type
private
FFilename: string;
FUnitName: string;
function GetFileUnitNameWithoutNamespace: string;
function GetIdentifierStartInUnitName: Integer;
public
constructor Create(const TheUnitName, TheFilename: string);
property FileUnitName: string read FUnitName;
property FileUnitNameWithoutNamespace: string read GetFileUnitNameWithoutNamespace;
property Filename: string read FFilename;
property IdentifierStartInUnitName: Integer read GetIdentifierStartInUnitName;
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,
Extensions: string; KeepDoubles, CaseInsensitive: boolean;
var TreeOfUnitFiles: TAVLTree): boolean;
Extensions, NameSpacePath: string; KeepDoubles, CaseInsensitive: boolean;
var TreeOfUnitFiles, TreeOfNamespaces: TAVLTree): boolean;
procedure FreeTreeOfUnitFiles(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);
function CompareUnitFileInfos(Data1, Data2: Pointer): integer;
function CompareNameSpaceInfos(Data1, Data2: Pointer): integer;
function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString,
UnitFileInfo: Pointer): integer;
function CompareNameSpaceAndNameSpaceInfo(NamespacePAnsiString,
NamespaceInfo: Pointer): integer;
//-----------------------------------------------------------------------------
// functions / procedures
@ -5636,15 +5663,61 @@ begin
System.Move(p^,Result[1],l);
end;
function GatherUnitFiles(const BaseDir, SearchPath,
Extensions: string; KeepDoubles, CaseInsensitive: boolean;
var TreeOfUnitFiles: TAVLTree): boolean;
procedure AddToTreeOfUnitFilesOrNamespaces(var TreeOfUnitFiles,
TreeOfNameSpaces: TAVLTree; const NameSpacePath, Filename: string;
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
// SearchPath: semicolon separated list of directories
// 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
// CaseInsensitive: true to ignore case on comparing extensions
// TreeOfUnitFiles: tree of TUnitFileInfo
// TreeOfNamespaces: tree of TNameSpaceInfo
var
SearchedDirectories: TAVLTree; // tree of AnsiString
@ -5760,8 +5833,8 @@ var
then
continue;
if ExtensionFits(FileInfo.Name) then begin
AddToTreeOfUnitFiles(TreeOfUnitFiles,ADirectory+FileInfo.Name,
KeepDoubles);
AddToTreeOfUnitFilesOrNamespaces(TreeOfUnitFiles, TreeOfNamespaces,
NameSpacePath, ADirectory+FileInfo.Name, CaseInsensitive, KeepDoubles);
end;
until FindNextUTF8(FileInfo)<>0;
end;
@ -5808,16 +5881,14 @@ begin
TreeOfUnitFiles.Free;
end;
procedure AddToTreeOfUnitFiles(var TreeOfUnitFiles: TAVLTree;
const Filename: string; KeepDoubles: boolean);
procedure AddToTreeOfUnitFiles(var TreeOfUnitFiles: TAVLTree; const Filename,
Unitname: string; KeepDoubles: boolean);
var
AnUnitName: String;
NewItem: TUnitFileInfo;
begin
AnUnitName:=ExtractFileNameOnly(Filename);
if (not KeepDoubles) then begin
if (TreeOfUnitFiles<>nil)
and (TreeOfUnitFiles.FindKey(Pointer(AnUnitName),
and (TreeOfUnitFiles.FindKey(Pointer(UnitName),
@CompareUnitNameAndUnitFileInfo)<>nil)
then begin
// an unit with the same name was already found and doubles are not
@ -5828,21 +5899,64 @@ begin
// add
if TreeOfUnitFiles=nil then
TreeOfUnitFiles:=TAVLTree.Create(@CompareUnitFileInfos);
NewItem:=TUnitFileInfo.Create(AnUnitName,Filename);
NewItem:=TUnitFileInfo.Create(UnitName,Filename);
TreeOfUnitFiles.Add(NewItem);
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;
begin
Result:=CompareIdentifiers(PChar(TUnitFileInfo(Data1).FileUnitName),
PChar(TUnitFileInfo(Data2).FileUnitName));
end;
function CompareNameSpaceInfos(Data1, Data2: Pointer): integer;
begin
Result:=CompareIdentifiers(PChar(TNameSpaceInfo(Data1).NameSpace),
PChar(TNameSpaceInfo(Data2).NameSpace));
end;
function CompareUnitNameAndUnitFileInfo(UnitnamePAnsiString,
UnitFileInfo: Pointer): integer;
begin
Result:=CompareIdentifiers(PChar(UnitnamePAnsiString),
PChar(TUnitFileInfo(UnitFileInfo).FileUnitName));
//do not use CompareIdentifiers - they compare only to the first "."
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;
function CountNeededLineEndsToAddForward(const Src: string;
@ -5973,6 +6087,16 @@ begin
Result:=CompareText(Txt1,Len1,Txt2,Len2,CaseSensitive);
end;
{ TNameSpaceInfo }
constructor TNameSpaceInfo.Create(const TheNamespace, TheFilename: string;
TheIdentifierStartInUnitName: Integer);
begin
FNamespace:=TheNamespace;
FFilename:=TheFilename;
FIdentifierStartInUnitName:=TheIdentifierStartInUnitName;
end;
{ TUnitFileInfo }
constructor TUnitFileInfo.Create(const TheUnitName, TheFilename: string);
@ -5981,6 +6105,27 @@ begin
FFilename:=TheFilename;
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;
ctnConstDefinition = 22;
ctnGlobalProperty = 23;
ctnUseUnit = 24; // StartPos=unitname, EndPos=unitname+inFilename
ctnUseUnit = 24; // StartPos=unit, EndPos=unitname+inFilename, children ctnUseUnitNamespace, ctnUseUnitClearName
ctnVarArgs = 25;
ctnUseUnitNamespace = 26; // <namespace>.clearname.pas
ctnUseUnitClearName = 27; // namespace.<clearname>.pas
ctnClass = 30;
ctnClassInterface = 31;
@ -194,7 +196,7 @@ const
ctnInitialization,ctnFinalization];
AllFindContextDescs = AllIdentifierDefinitions + AllCodeSections + AllClasses +
[ctnProcedure];
AllPointContexts = AllClasses+AllSourceTypes+[ctnEnumerationType,ctnInterface,ctnImplementation,ctnTypeType];
AllPointContexts = AllClasses+AllSourceTypes+[ctnEnumerationType,ctnInterface,ctnImplementation,ctnTypeType,ctnUseUnitNamespace,ctnUseUnitClearName];
// CodeTreeNodeSubDescriptors
@ -397,6 +399,8 @@ begin
ctnPackage: Result:='Package';
ctnLibrary: Result:='Library';
ctnUnit: Result:='Unit';
ctnUseUnitNamespace: Result:='Namespace';
ctnUseUnitClearName: Result:='Unit name without namespace';
ctnInterface: Result:='Interface Section';
ctnImplementation: Result:='Implementation';
ctnInitialization: Result:='Initialization';

View File

@ -2191,7 +2191,16 @@ begin
{$IFDEF CTDEBUG}
DebugLn('TFindDeclarationTool.FindDeclaration D CursorNode=',NodeDescriptionAsString(CursorNode.Desc),' HasChildren=',dbgs(CursorNode.FirstChild<>nil));
{$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
//DebugLn(['TFindDeclarationTool.FindDeclaration IsUsesSection']);
Result:=FindDeclarationInUsesSection(CursorNode,CleanCursorPos,
@ -2751,7 +2760,10 @@ begin
ReadNextAtom;
if not UpAtomIs('USES') then
RaiseUsesExpected;
end;
end else
if (UsesNode.Desc = ctnUseUnitClearName) then
MoveCursorToNodeStart(UsesNode.Parent);
repeat
ReadNextAtom; // read name
if CurPos.StartPos>CleanPos then break;
@ -3261,11 +3273,20 @@ begin
end;
end;
ctnUseUnit:
ctnUseUnitNamespace:
begin
// hint for unit namespace in "uses" section
Result += 'namespace ';
MoveCursorToNodeStart(Node);
ReadNextAtom;
Result := Result + GetAtom;
end;
ctnUseUnitClearName:
begin
// hint for unit in "uses" section
Result += 'unit ';
MoveCursorToNodeStart(Node);
MoveCursorToNodeStart(Node.Parent);
Result := Result + ReadIdentifierWithDots;
end
@ -3974,6 +3995,55 @@ var
//debugln(['SearchInHelpers 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;
const
AbortNoCacheResult = false;
@ -4212,6 +4282,14 @@ begin
exit;
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
SearchInHelpersInTheEnd := False;
if (fdfSearchInHelpers in Flags)
@ -6127,6 +6205,8 @@ begin
ListOfPCodeXYPosition:=nil;
BuildTreeAndGetCleanPos(CursorPos,CleanPos);
Node:=FindDeepestNodeAtPos(CleanPos,true);
if Node.Desc in [ctnUseUnitNamespace,ctnUseUnitClearName] then
Node:=Node.Parent;
if Node.Desc<>ctnUseUnit then
RaiseException('This function needs the cursor at a unit in a uses clause');
// cursor is on an used unit -> try to locate it
@ -7333,19 +7413,20 @@ begin
Node:=UsesNode.LastChild;
while Node<>nil do begin
if (fdfCollect in Params.Flags) then begin
CollectResult:=DoOnIdentifierFound(Params,Node);
CollectResult:=DoOnIdentifierFound(Params,Node.FirstChild);
if CollectResult=ifrAbortSearch then begin
Result:=false;
exit;
end else if CollectResult=ifrSuccess then begin
Result:=true;
Params.SetResult(Self,Node);
Params.SetResult(Self,Node.FirstChild);
exit;
end;
end else if CompareSrcIdentifiers(Node.StartPos,Params.Identifier) then begin
// the searched identifier was a uses AUnitName, point to the identifier in
// 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;
exit;
end;
@ -8525,7 +8606,7 @@ var
{$IFDEF ShowExprEval}
debugln([' FindExpressionTypeOfTerm ResolveUseUnit used unit -> interface node ',dbgstr(ExprType.Context.Tool.ExtractNode(ExprType.Context.Node,[]))]);
{$ENDIF}
AnUnitName:=aTool.ExtractUsedUnitName(ExprType.Context.Node,@InFilename);
AnUnitName:=aTool.ExtractUsedUnitName(ExprType.Context.Node.Parent,@InFilename);
NewCodeTool:=aTool.FindCodeToolForUsedUnit(AnUnitName,InFilename,true);
NewCodeTool.BuildInterfaceIdentifierCache(true);
NewNode:=NewCodeTool.FindInterfaceNode;
@ -8568,7 +8649,7 @@ var
ExprType.Context.Node:=ExprType.Context.Tool.GetInterfaceNode;
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
ResolveUseUnit;
end

View File

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

View File

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

View File

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

View File

@ -322,12 +322,18 @@ begin
s:='label';
end;
ctnUnit, ctnUseUnit:
ctnUnit, ctnUseUnitClearName:
begin
AColor:=clBlack;
s:='unit';
end;
ctnUseUnitNamespace:
begin
AColor:=clBlack;
s:='namespace';
end;
ctnNone:
if iliKeyword in IdentItem.Flags then begin
AColor:=clBlack;
@ -544,13 +550,29 @@ function FindUnitName(IdentList: TIdentifierList;
IdentItem: TIdentifierListItem): string;
var
CodeBuf: TCodeBuffer;
LastPointPos: Integer;
begin
Result:=IdentItem.Identifier;
CodeBuf:=CodeToolBoss.FindUnitSource(IdentList.StartContextPos.Code,Result,'');
if CodeBuf=nil then exit;
Result:=CodeToolBoss.GetSourceName(CodeBuf,true);
if IdentItem is TUnitNameSpaceIdentifierListItem then
begin
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
Result:=IdentItem.Identifier;
Result:=IdentItem.Identifier
else
begin
LastPointPos := LastDelimiter('.', Result);
if LastPointPos > 0 then
Result := Copy(Result, LastPointPos+1, High(Integer));
end;
end;
function GetIdentCompletionValue(aCompletion : TSynCompletion;
@ -617,7 +639,7 @@ begin
IsReadOnly:=IdentItem.IsPropertyReadOnly;
end;
ctnUnit, ctnPackage, ctnLibrary:
ctnUnit, ctnPackage, ctnLibrary, ctnUseUnitNamespace:
ValueType:=icvUnitName;
end;
@ -739,7 +761,7 @@ begin
end;
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
then
Result+='.';