codetools: add compiler functions into system., filter predefined compiler functions, patch #28320

git-svn-id: trunk@49474 -
This commit is contained in:
mattias 2015-06-30 09:22:06 +00:00
parent 4c1d902065
commit eec44bce79
5 changed files with 115 additions and 105 deletions

View File

@ -47,7 +47,8 @@ type
cafSemicolon, cafEqual, cafColon, cafComma, cafPoint, cafSemicolon, cafEqual, cafColon, cafComma, cafPoint,
cafRoundBracketOpen, cafRoundBracketClose, cafRoundBracketOpen, cafRoundBracketClose,
cafEdgedBracketOpen, cafEdgedBracketClose, cafEdgedBracketOpen, cafEdgedBracketClose,
cafWord, cafEnd cafWord, cafEnd,
cafOtherOperator // = other operator
); );
TCommonAtomFlags = set of TCommonAtomFlag; TCommonAtomFlags = set of TCommonAtomFlag;
@ -58,7 +59,7 @@ const
'Semicolon', 'Equal', 'Colon', 'Comma', 'Point', 'Semicolon', 'Equal', 'Colon', 'Comma', 'Point',
'RoundBracketOpen', 'RoundBracketClose', 'RoundBracketOpen', 'RoundBracketClose',
'EdgedBracketOpen', 'EdgedBracketClose', 'EdgedBracketOpen', 'EdgedBracketClose',
'Word', 'End' 'Word', 'End', 'Operator'
); );
type type

View File

@ -1740,7 +1740,7 @@ begin
if CurPos.StartPos>1 then begin if CurPos.StartPos>1 then begin
c1:=Src[CurPos.StartPos-1]; c1:=Src[CurPos.StartPos-1];
// test for double char operators :=, +=, -=, /=, *=, <>, <=, >=, **, >< // test for double char operators :=, +=, -=, /=, *=, <>, <=, >=, **, ><
if ((c2='=') and (IsEqualOperatorStartChar[c1])) if ((c2='=') and (IsEqualOperatorStartChar[c1]))
or ((c1='<') and (c2='>')) or ((c1='<') and (c2='>'))
or ((c1='>') and (c2='<')) or ((c1='>') and (c2='<'))
or ((c1='.') and (c2='.')) or ((c1='.') and (c2='.'))
@ -1748,7 +1748,7 @@ begin
or ((c1='@') and (c2='@')) or ((c1='@') and (c2='@'))
then begin then begin
dec(CurPos.StartPos); dec(CurPos.StartPos);
CurPos.Flag:=cafNone; CurPos.Flag:=cafOtherOperator;
end else begin end else begin
case c2 of case c2 of
'=': CurPos.Flag:=cafEqual; '=': CurPos.Flag:=cafEqual;

View File

@ -7894,7 +7894,7 @@ var
if (Context.Node = nil) then if (Context.Node = nil) then
begin begin
if (ExprType.Desc in xtAllPredefinedTypes) then if (ExprType.Desc in xtAllIdentPredefinedTypes) then
begin begin
//no problem, we found predefined basic type (e.g. string) without a context! //no problem, we found predefined basic type (e.g. string) without a context!
//find class helpers! //find class helpers!
@ -8089,7 +8089,7 @@ var
RaiseIdentExpected; RaiseIdentExpected;
end; end;
ResolveChildren; ResolveChildren;
if ExprType.Desc in xtAllPredefinedTypes then begin if ExprType.Desc in xtAllIdentPredefinedTypes then begin
//Lazarus supports record helpers for basic types (string) as well (with TYPEHELPERS modeswitch!). //Lazarus supports record helpers for basic types (string) as well (with TYPEHELPERS modeswitch!).
end else if (ExprType.Context.Node=nil) then begin end else if (ExprType.Context.Node=nil) then begin
MoveCursorToCleanPos(CurAtom.StartPos); MoveCursorToCleanPos(CurAtom.StartPos);

View File

@ -194,7 +194,8 @@ type
ilcfNeedsDo, // after context a 'do' is needed. e.g. 'with Form1| do' ilcfNeedsDo, // after context a 'do' is needed. e.g. 'with Form1| do'
ilcfIsExpression, // is expression part of statement. e.g. 'if expr' ilcfIsExpression, // is expression part of statement. e.g. 'if expr'
ilcfCanProcDeclaration,// context allows one to declare a procedure/method ilcfCanProcDeclaration,// context allows one to declare a procedure/method
ilcfEndOfLine // atom at end of line ilcfEndOfLine, // atom at end of line
ilcfDontAllowProcedures// context doesn't allow procedures (e.g. in function parameter, after assignment or other operator, in if codition etc.)
); );
TIdentifierListContextFlags = set of TIdentifierListContextFlag; TIdentifierListContextFlags = set of TIdentifierListContextFlag;
@ -372,9 +373,9 @@ type
function CollectAllIdentifiers(Params: TFindDeclarationParams; function CollectAllIdentifiers(Params: TFindDeclarationParams;
const FoundContext: TFindContext): TIdentifierFoundResult; const FoundContext: TFindContext): TIdentifierFoundResult;
procedure GatherPredefinedIdentifiers(CleanPos: integer; procedure GatherPredefinedIdentifiers(CleanPos: integer;
const Context: TFindContext); const Context, GatherContext: TFindContext);
procedure GatherUsefulIdentifiers(CleanPos: integer; procedure GatherUsefulIdentifiers(CleanPos: integer;
const Context: TFindContext); const Context, GatherContext: TFindContext);
procedure GatherUnitnames; procedure GatherUnitnames;
procedure GatherSourceNames(const Context: TFindContext); procedure GatherSourceNames(const Context: TFindContext);
procedure GatherContextKeywords(const Context: TFindContext; procedure GatherContextKeywords(const Context: TFindContext;
@ -675,6 +676,14 @@ procedure TIdentifierList.Add(NewItem: TIdentifierListItem);
var var
AnAVLNode: TAVLTreeNode; AnAVLNode: TAVLTreeNode;
begin begin
if (ilcfDontAllowProcedures in ContextFlags) and (NewItem.GetDesc = ctnProcedure) and
not (NewItem.IsFunction or NewItem.IsContructor)
then
begin
NewItem.Free;
Exit;
end;
AnAVLNode:=FIdentView.FindKey(NewItem,@CompareIdentListItemsForIdents); AnAVLNode:=FIdentView.FindKey(NewItem,@CompareIdentListItemsForIdents);
if AnAVLNode=nil then begin if AnAVLNode=nil then begin
if History<>nil then if History<>nil then
@ -904,8 +913,7 @@ var
NewItem: TIdentifierListItem; NewItem: TIdentifierListItem;
begin begin
//DebugLn(['AddCompilerProcedure ',AProcName,' ',ilcfStartOfStatement in CurrentIdentifierList.ContextFlags]); //DebugLn(['AddCompilerProcedure ',AProcName,' ',ilcfStartOfStatement in CurrentIdentifierList.ContextFlags]);
if not (ilcfStartOfStatement in CurrentIdentifierList.ContextFlags) then exit; if (ilcfDontAllowProcedures in CurrentIdentifierList.ContextFlags) then exit;
if not (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) then exit;
NewItem:=TIdentifierListItem.Create( NewItem:=TIdentifierListItem.Create(
icompUnknown, icompUnknown,
@ -939,8 +947,6 @@ procedure TIdentCompletionTool.AddCompilerFunction(const AProcName, AParameterLi
var var
NewItem: TIdentifierListItem; NewItem: TIdentifierListItem;
begin begin
if not (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) then exit;
NewItem:=TIdentifierListItem.Create( NewItem:=TIdentifierListItem.Create(
icompUnknown, icompUnknown,
false, false,
@ -1258,7 +1264,7 @@ begin
end; end;
procedure TIdentCompletionTool.GatherPredefinedIdentifiers(CleanPos: integer; procedure TIdentCompletionTool.GatherPredefinedIdentifiers(CleanPos: integer;
const Context: TFindContext); const Context, GatherContext: TFindContext);
// Add predefined identifiers // Add predefined identifiers
function StatementLevel: integer; function StatementLevel: integer;
@ -1296,11 +1302,21 @@ var
ProcNode: TCodeTreeNode; ProcNode: TCodeTreeNode;
HidddnUnits: String; HidddnUnits: String;
p: PChar; p: PChar;
SystemTool: TFindDeclarationTool;
I: TExpressionTypeDesc;
InSystemContext: Boolean;
begin begin
if not (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) then exit;
if CleanPos=0 then ; if CleanPos=0 then ;
if Context.Node.Desc in AllPascalStatements then begin SystemTool := FindCodeToolForUsedUnit('System','',False);
InSystemContext :=
(ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) or
((ilcfStartIsSubIdent in CurrentIdentifierList.ContextFlags) and
(GatherContext.Tool<>nil) and (GatherContext.Node<>nil) and (SystemTool<>nil) and
(GatherContext.Tool = SystemTool) and (GatherContext.Node = SystemTool.FindInterfaceNode));
if InSystemContext and (Context.Node.Desc in AllPascalStatements) then
begin
// see fpc/compiler/psystem.pp // see fpc/compiler/psystem.pp
AddCompilerProcedure('Assert','Condition:Boolean;const Message:String'); AddCompilerProcedure('Assert','Condition:Boolean;const Message:String');
AddCompilerFunction('Assigned','P:Pointer','Boolean'); AddCompilerFunction('Assigned','P:Pointer','Boolean');
@ -1347,7 +1363,12 @@ begin
AddCompilerProcedure('Write','Args:Arguments'); AddCompilerProcedure('Write','Args:Arguments');
AddCompilerProcedure('WriteLn','Args:Arguments'); AddCompilerProcedure('WriteLn','Args:Arguments');
AddCompilerProcedure('WriteStr','var S:String;Args:Arguments'); AddCompilerProcedure('WriteStr','var S:String;Args:Arguments');
end;
if (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) and
(Context.Node.Desc in AllPascalStatements)
then
begin
if (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) if (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags)
and Context.Tool.NodeIsInAMethod(Context.Node) and Context.Tool.NodeIsInAMethod(Context.Node)
and (not CurrentIdentifierList.HasIdentifier('Self','')) then begin and (not CurrentIdentifierList.HasIdentifier('Self','')) then begin
@ -1382,57 +1403,41 @@ begin
end; end;
// system types // system types
AddBaseType('Char'); if InSystemContext then
AddBaseType('WideChar'); begin
AddBaseType('Real'); for I := Low(I) to High(I) do
AddBaseType('Single'); begin
AddBaseType('Double'); case I of
AddBaseType('Extended'); xtChar..xtPointer, xtLongint..xtByte:
AddBaseType('CExtended'); AddBaseType(PChar(ExpressionTypeDescNames[I]));
AddBaseType('Currency'); xtFile, xtText:
AddBaseType('Comp'); if not (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then
AddBaseType('Int64'); AddBaseType(PChar(ExpressionTypeDescNames[I]));
AddBaseType('Cardinal'); end;
AddBaseType('QWord'); end;
AddBaseType('Boolean'); AddBaseConstant('True');
AddBaseType('ByteBool'); AddBaseConstant('False');
AddBaseType('WordBool'); //the nil constant doesn't belong to system context, therefore it is added in next step
AddBaseType('LongBool');
AddBaseType('QWordBool');
AddBaseType('String');
AddBaseType('AnsiString');
AddBaseType('ShortString');
AddBaseType('WideString');
AddBaseType('UnicodeString');
AddBaseType('Pointer');
AddBaseType('LongInt');
AddBaseType('Word');
AddBaseType('SmallInt');
AddBaseType('ShortInt');
AddBaseType('Byte');
if not (ilcfStartInStatement in CurrentIdentifierList.ContextFlags) then begin
AddBaseType('File');
AddBaseType('Text');
end; end;
AddBaseConstant('Nil'); if (ilcfStartOfOperand in CurrentIdentifierList.ContextFlags) then
AddBaseConstant('True'); begin
AddBaseConstant('False'); AddBaseConstant(PChar(ExpressionTypeDescNames[xtNil]));
// system units
// system units HidddnUnits:=Scanner.GetHiddenUsedUnits;
HidddnUnits:=Scanner.GetHiddenUsedUnits; if HidddnUnits<>'' then begin
if HidddnUnits<>'' then begin p:=PChar(HidddnUnits);
p:=PChar(HidddnUnits); while p^<>#0 do begin
while p^<>#0 do begin while p^=',' do inc(p);
while p^=',' do inc(p); if GetIdentLen(p)>0 then
if GetIdentLen(p)>0 then AddSystemUnit(p);
AddSystemUnit(p); while not (p^ in [',',#0]) do inc(p);
while not (p^ in [',',#0]) do inc(p); end;
end; end;
end; end;
end; end;
procedure TIdentCompletionTool.GatherUsefulIdentifiers(CleanPos: integer; procedure TIdentCompletionTool.GatherUsefulIdentifiers(CleanPos: integer;
const Context: TFindContext); const Context, GatherContext: TFindContext);
procedure AddPropertyProc(ProcName: string); procedure AddPropertyProc(ProcName: string);
var var
@ -1449,7 +1454,7 @@ var
PropertyName: String; PropertyName: String;
begin begin
//debugln(['TIdentCompletionTool.GatherUsefulIdentifiers ',CleanPosToStr(CleanPos),' ',dbgsFC(Context)]); //debugln(['TIdentCompletionTool.GatherUsefulIdentifiers ',CleanPosToStr(CleanPos),' ',dbgsFC(Context)]);
GatherPredefinedIdentifiers(CleanPos,Context); GatherPredefinedIdentifiers(CleanPos,Context,GatherContext);
if Context.Node.Desc=ctnProperty then begin if Context.Node.Desc=ctnProperty then begin
PropertyName:=ExtractPropName(Context.Node,false); PropertyName:=ExtractPropName(Context.Node,false);
//debugln('TIdentCompletionTool.GatherUsefulIdentifiers Property ',PropertyName); //debugln('TIdentCompletionTool.GatherUsefulIdentifiers Property ',PropertyName);
@ -2569,43 +2574,6 @@ begin
CursorContext:=CreateFindContext(Self,CursorNode); CursorContext:=CreateFindContext(Self,CursorNode);
GatherContextKeywords(CursorContext,IdentStartPos,Beautifier); GatherContextKeywords(CursorContext,IdentStartPos,Beautifier);
// search and gather identifiers in context
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers D CONTEXT: ',
GatherContext.Tool.MainFilename,
' ',GatherContext.Node.DescAsString,
' "',StringToPascalConst(copy(GatherContext.Tool.Src,GatherContext.Node.StartPos,50)),'"');
{$ENDIF}
// gather all identifiers in context
Params.ContextNode:=GatherContext.Node;
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers];
if (Params.ContextNode.Desc=ctnInterface) and StartInSubContext then
Include(Params.Flags,fdfIgnoreUsedUnits);
if not StartInSubContext then
Include(Params.Flags,fdfSearchInParentNodes);
if Params.ContextNode.Desc in AllClasses then
Exclude(Params.Flags,fdfSearchInParentNodes);
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers F');
{$ENDIF}
CurrentIdentifierList.Context:=GatherContext;
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 // check for incomplete context
// context bracket level // context bracket level
@ -2653,8 +2621,12 @@ begin
then begin then begin
// todo: check at start of expression, not only in front of variable // todo: check at start of expression, not only in front of variable
CurrentIdentifierList.ContextFlags:= CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfIsExpression]; CurrentIdentifierList.ContextFlags+[ilcfIsExpression, ilcfDontAllowProcedures];
end; end;
// check if procedure is allowed
if CurPos.Flag in [cafComma, cafRoundBracketOpen, cafEdgedBracketOpen, cafEqual, cafOtherOperator] then
CurrentIdentifierList.ContextFlags:=
CurrentIdentifierList.ContextFlags+[ilcfDontAllowProcedures];
end; end;
end; end;
// context behind // context behind
@ -2728,6 +2700,43 @@ begin
CurrentIdentifierList.ContextFlags+[ilcfEndOfLine]; CurrentIdentifierList.ContextFlags+[ilcfEndOfLine];
end; end;
// search and gather identifiers in context
if (GatherContext.Tool<>nil) and (GatherContext.Node<>nil) then begin
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers D CONTEXT: ',
GatherContext.Tool.MainFilename,
' ',GatherContext.Node.DescAsString,
' "',StringToPascalConst(copy(GatherContext.Tool.Src,GatherContext.Node.StartPos,50)),'"');
{$ENDIF}
// gather all identifiers in context
Params.ContextNode:=GatherContext.Node;
Params.SetIdentifier(Self,nil,@CollectAllIdentifiers);
Params.Flags:=[fdfSearchInAncestors,fdfCollect,fdfFindVariable,fdfSearchInHelpers];
if (Params.ContextNode.Desc=ctnInterface) and StartInSubContext then
Include(Params.Flags,fdfIgnoreUsedUnits);
if not StartInSubContext then
Include(Params.Flags,fdfSearchInParentNodes);
if Params.ContextNode.Desc in AllClasses then
Exclude(Params.Flags,fdfSearchInParentNodes);
{$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers F');
{$ENDIF}
CurrentIdentifierList.Context:=GatherContext;
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 procedure/method declaration context // check for procedure/method declaration context
CheckProcedureDeclarationContext; CheckProcedureDeclarationContext;
@ -2735,7 +2744,7 @@ begin
{$IFDEF CTDEBUG} {$IFDEF CTDEBUG}
DebugLn('TIdentCompletionTool.GatherIdentifiers G'); DebugLn('TIdentCompletionTool.GatherIdentifiers G');
{$ENDIF} {$ENDIF}
GatherUsefulIdentifiers(IdentStartPos,CursorContext); GatherUsefulIdentifiers(IdentStartPos,CursorContext,GatherContext);
end; end;
Result:=true; Result:=true;

View File

@ -2438,7 +2438,7 @@ begin
CacheWasUsed:=true; CacheWasUsed:=true;
AnOwner := nil; AnOwner := nil;
if (CTExprType.Desc in xtAllPredefinedTypes) then if (CTExprType.Desc in xtAllIdentPredefinedTypes) then
CTExprType.Context.Tool := CodeToolBoss.CurCodeTool.FindCodeToolForUsedUnit('system','',false); CTExprType.Context.Tool := CodeToolBoss.CurCodeTool.FindCodeToolForUsedUnit('system','',false);
CTTool := CTExprType.Context.Tool; CTTool := CTExprType.Context.Tool;
CTNode := CTExprType.Context.Node; CTNode := CTExprType.Context.Node;
@ -2457,7 +2457,7 @@ begin
for n:=1 to 30 do begin for n:=1 to 30 do begin
if (CTExprType.Desc=xtContext) and (CTNode<>nil) then if (CTExprType.Desc=xtContext) and (CTNode<>nil) then
ElementName:=CodeNodeToElementName(CTTool,CTNode) ElementName:=CodeNodeToElementName(CTTool,CTNode)
else if (CTExprType.Desc in xtAllPredefinedTypes) then else if (CTExprType.Desc in xtAllIdentPredefinedTypes) then
ElementName:=ExpressionTypeDescNames[CTExprType.Desc] ElementName:=ExpressionTypeDescNames[CTExprType.Desc]
else else
break; break;
@ -2660,7 +2660,7 @@ begin
// add declaration // add declaration
if Desc=xtContext then if Desc=xtContext then
CTHint:=Tool.GetSmartHint(Node,XYPos,false) CTHint:=Tool.GetSmartHint(Node,XYPos,false)
else if Desc in xtAllPredefinedTypes then else if Desc in xtAllIdentPredefinedTypes then
CTHint:='type '+ExpressionTypeDescNames[Desc]; CTHint:='type '+ExpressionTypeDescNames[Desc];
Result:=Result+' <nobr>'+SourceToFPDocHint(CTHint)+'</nobr>'; Result:=Result+' <nobr>'+SourceToFPDocHint(CTHint)+'</nobr>';
@ -2669,7 +2669,7 @@ begin
if XYPos.Code=nil then begin if XYPos.Code=nil then begin
if (Node<>nil) then if (Node<>nil) then
Tool.CleanPosToCaret(Node.StartPos,XYPos) Tool.CleanPosToCaret(Node.StartPos,XYPos)
else if Desc in xtAllPredefinedTypes then else if Desc in xtAllIdentPredefinedTypes then
Tool.CleanPosToCaret(Tool.Tree.Root.StartPos,XYPos); Tool.CleanPosToCaret(Tool.Tree.Root.StartPos,XYPos);
end; end;
Result:=Result+' '+SourcePosToFPDocHint(XYPos)+LineEnding; Result:=Result+' '+SourcePosToFPDocHint(XYPos)+LineEnding;