1 unit NoSpaceAfter;
2 
3 { AFS 9 Dec 1999
4   no space after  certain tokens }
5 
6 {(*}
7 (*------------------------------------------------------------------------------
8  Delphi Code formatter source code
9 
10 The Original Code is NoSpaceAfter, released May 2003.
11 The Initial Developer of the Original Code is Anthony Steele.
12 Portions created by Anthony Steele are Copyright (C) 1999-2008 Anthony Steele.
13 All Rights Reserved.
14 Contributor(s): Anthony Steele.
15 
16 The contents of this file are subject to the Mozilla Public License Version 1.1
17 (the "License"). you may not use this file except in compliance with the License.
18 You may obtain a copy of the License at http://www.mozilla.org/NPL/
19 
20 Software distributed under the License is distributed on an "AS IS" basis,
21 WITHOUT WARRANTY OF ANY KIND, either express or implied.
22 See the License for the specific language governing rights and limitations
23 under the License.
24 
25 Alternatively, the contents of this file may be used under the terms of
26 the GNU General Public License Version 2 or later (the "GPL")
27 See http://www.gnu.org/licenses/gpl.html
28 ------------------------------------------------------------------------------*)
29 {*)}
30 
31 {$I JcfGlobal.inc}
32 
33 interface
34 
35 uses SwitchableVisitor, SourceToken;
36 
37 type
38   TNoSpaceAfter = class(TSwitchableVisitor)
39   private
40     fcLastSolidToken: TSourceToken;
41     fbSafeToRemoveReturn: boolean;  // this taken from NoReturnBefore
42   protected
EnabledVisitSourceTokennull43     function EnabledVisitSourceToken(const pcNode: TObject): boolean; override;
44   public
45     constructor Create; override;
46 
IsIncludedInSettingsnull47     function IsIncludedInSettings: boolean; override;
48   end;
49 
50 
51 implementation
52 
53 uses
54   JcfStringUtils,
55   Tokens, ParseTreeNodeType, JcfSettings, FormatFlags,
56   TokenUtils, SettingsTypes;
57 
58 { TNoSpaceAfter }
59 
60 
NeedsNoSpacenull61 function NeedsNoSpace(const pt, ptNext: TSourceToken): boolean;
62 const
63   NoSpaceAnywhere: TTokenTypeSet = [ttOpenBracket, ttOpenSquareBracket, ttDot];
64 begin
65   Result := False;
66 
67   if pt = nil then
68     exit;
69 
70   { if the next thing is a comment, leave well enough alone }
71   if ptNext.TokenType = ttComment then
72     exit;
73 
74   if (pt.TokenType in [ttLessThan,ttGreaterThan]) and pt.HasParentNode(nGeneric,1) then
75     exit(True);
76 
77   if pt.TokenType in NoSpaceAnywhere then
78     exit(True);
79 
80   if (FormattingSettings.Spaces.SpaceForOperator = eNever) then
81     if IsSymbolOperator(pt) then
82       exit(True);
83 
84   { no space between method name and open bracket for param list
85     no space between type & bracket for cast
86     no space between fn name & params for procedure call }
87   if pt.HasParentNode([nProcedureDecl, nFunctionDecl, nConstructorDecl,
88     nDestructorDecl, nStatementList]) and
89     (IsIdentifier(pt, idAllowDirectives) or (pt.TokenType in BuiltInTypes))
90   then
91     if (ptNext.TokenType in OpenBrackets) and (not IsInsideAsm(ptNext)) then
92       exit(True);
93 
94   { the above takes care of procedure headers but not procedure type defs
95    eg type TFred = procedure(i: integer) of object;
96     note no space before the open bracket }
97   if pt.HasParentNode(nTypeDecl) and (pt.IsOnRightOf(nTypeDecl, ttEquals)) and
98     (pt.TokenType in ProcedureWords)
99   then
100     if (ptNext.TokenType in OpenBrackets) then
101       exit(True);
102 
103   { no space after unary operator in expression }
104   if pt.HasParentNode(nExpression) and IsUnaryOperator(pt) and (not StrHasAlpha(pt.SourceCode)) then
105     exit(True);
106 
107   { no space before class heritage ? could be one of 3 things
108     TFoo = class; - no space, but "No space before semicolon" should take care of that
109     TBar = class(TBaz) - no space unless you are Marcel van Brakel
110     TWibble = class of TFish - has space
111 
112     see SingleSpaceAfter
113 
114     also applies to type TFoo = interface(IDispatch) }
115   if (pt.HasParentNode(nRestrictedType)) and (pt.TokenType in ObjectTypeWords) and
116     ( not (FormattingSettings.Spaces.SpaceBeforeClassHeritage))
117   then
118     if (ptNext.TokenType in [ttOpenBracket, ttSemiColon]) then
119       exit(True);
120 end;
121 
122 constructor TNoSpaceAfter.Create;
123 begin
124   inherited;
125   fbSafeToRemoveReturn := True;
126   FormatFlags := FormatFlags + [eRemoveSpace];
127 end;
128 
EnabledVisitSourceTokennull129 function TNoSpaceAfter.EnabledVisitSourceToken(const pcNode: TObject): boolean;
130 var
131   lcSourceToken: TSourceToken;
132   lcNextSolid:   TSourceToken;
133 begin
134   Result := False;
135   lcSourceToken := TSourceToken(pcNode);
136 
137   if lcSourceToken.TokenType = ttWhiteSpace then
138   begin
139     lcNextSolid := lcSourceToken.NextTokenWithExclusions([ttWhiteSpace, ttReturn]);
140     if lcNextSolid <> nil then
141     begin
142       if NeedsNoSpace(fcLastSolidToken, lcNextSolid) then
143         BlankToken(lcSourceToken);
144     end;
145   end
146   else
147   begin
148     { store for next time }
149     if not (lcSourceToken.TokenType in [ttWhiteSpace, ttReturn]) then
150       fcLastSolidToken := lcSourceToken;
151   end;
152 end;
153 
IsIncludedInSettingsnull154 function TNoSpaceAfter.IsIncludedInSettings: boolean;
155 begin
156   Result := FormattingSettings.Spaces.FixSpacing;
157 end;
158 
159 end.
160