lazarus/components/jcf2/Process/Spacing/NoSpaceAfter.pas

183 lines
4.9 KiB
ObjectPascal

unit NoSpaceAfter;
{ AFS 9 Dec 1999
no space after certain tokens }
{(*}
(*------------------------------------------------------------------------------
Delphi Code formatter source code
The Original Code is NoSpaceAfter, released May 2003.
The Initial Developer of the Original Code is Anthony Steele.
Portions created by Anthony Steele are Copyright (C) 1999-2008 Anthony Steele.
All Rights Reserved.
Contributor(s): Anthony Steele.
The contents of this file are subject to the Mozilla Public License Version 1.1
(the "License"). you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied.
See the License for the specific language governing rights and limitations
under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 2 or later (the "GPL")
See http://www.gnu.org/licenses/gpl.html
------------------------------------------------------------------------------*)
{*)}
{$I JcfGlobal.inc}
interface
uses SwitchableVisitor, SourceToken;
type
TNoSpaceAfter = class(TSwitchableVisitor)
private
fcLastSolidToken: TSourceToken;
fbSafeToRemoveReturn: boolean; // this taken from NoReturnBefore
protected
function EnabledVisitSourceToken(const pcNode: TObject): boolean; override;
public
constructor Create; override;
function IsIncludedInSettings: boolean; override;
end;
implementation
uses
JcfStringUtils,
Tokens, ParseTreeNodeType, JcfSettings, FormatFlags,
TokenUtils, SettingsTypes;
{ TNoSpaceAfter }
function NeedsNoSpace(const pt, ptNext: TSourceToken): boolean;
const
NoSpaceAnywhere: TTokenTypeSet = [ttOpenBracket, ttOpenSquareBracket, ttDot];
begin
Result := False;
if pt = nil then
exit;
{ if the next thing is a comment, leave well enough alone }
if ptNext.TokenType = ttComment then
exit;
if pt.TokenType in NoSpaceAnywhere then
begin
Result := True;
exit;
end;
if (FormattingSettings.Spaces.SpaceForOperator = eNever) then
begin
if IsSymbolOperator(pt) then
begin
Result := True;
exit;
end;
end;
{ no space between method name and open bracket for param list
no space between type & bracket for cast
no space between fn name & params for procedure call }
if pt.HasParentNode([nProcedureDecl, nFunctionDecl, nConstructorDecl,
nDestructorDecl, nStatementList]) and
(IsIdentifier(pt, idAllowDirectives) or (pt.TokenType in BuiltInTypes)) then
begin
if (ptNext.TokenType in OpenBrackets) and (not IsInsideAsm(ptNext)) then
begin
Result := True;
exit;
end;
end;
{ the above takes care of procedure headers but not procedure type defs
eg type TFred = procedure(i: integer) of object;
note no space before the open bracket }
if pt.HasParentNode(nTypeDecl) and (pt.IsOnRightOf(nTypeDecl, ttEquals)) and
(pt.TokenType in ProcedureWords) then
begin
if (ptNext.TokenType in OpenBrackets) then
begin
Result := True;
exit;
end;
end;
{ no space after unary operator in expression }
if pt.HasParentNode(nExpression) and IsUnaryOperator(pt) and
( not StrHasAlpha(pt.SourceCode)) then
begin
Result := True;
exit;
end;
{ no space before class heritage ? could be one of 3 things
TFoo = class; - no space, but "No space before semicolon" should take care of that
TBar = class(TBaz) - no space unless you are Marcel van Brakel
TWibble = class of TFish - has space
see SingleSpaceAfter
also applies to type TFoo = interface(IDispatch) }
if (pt.HasParentNode(nRestrictedType)) and (pt.TokenType in ObjectTypeWords) and
( not (FormattingSettings.Spaces.SpaceBeforeClassHeritage)) then
begin
if (ptNext.TokenType in [ttOpenBracket, ttSemiColon]) then
begin
Result := True;
exit;
end;
end;
end;
constructor TNoSpaceAfter.Create;
begin
inherited;
fbSafeToRemoveReturn := True;
FormatFlags := FormatFlags + [eRemoveSpace];
end;
function TNoSpaceAfter.EnabledVisitSourceToken(const pcNode: TObject): boolean;
var
lcSourceToken: TSourceToken;
lcNextSolid: TSourceToken;
begin
Result := False;
lcSourceToken := TSourceToken(pcNode);
if lcSourceToken.TokenType = ttWhiteSpace then
begin
lcNextSolid := lcSourceToken.NextTokenWithExclusions([ttWhiteSpace, ttReturn]);
if lcNextSolid <> nil then
begin
if NeedsNoSpace(fcLastSolidToken, lcNextSolid) then
BlankToken(lcSourceToken);
end;
end
else
begin
{ store for next time }
if not (lcSourceToken.TokenType in [ttWhiteSpace, ttReturn]) then
fcLastSolidToken := lcSourceToken;
end;
end;
function TNoSpaceAfter.IsIncludedInSettings: boolean;
begin
Result := FormattingSettings.Spaces.FixSpacing;
end;
end.