PageRenderTime 34ms CodeModel.GetById 29ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/components/jcf2/Process/Returns/NoReturnBefore.pas

http://github.com/graemeg/lazarus
Pascal | 211 lines | 123 code | 33 blank | 55 comment | 21 complexity | 38b7f41701276aefb834c38d1332bbdd MD5 | raw file
  1unit NoReturnBefore;
  2
  3{ AFS 11 Jan 2003
  4  Some tokens should not have a return before them for fomatting
  5}
  6
  7{(*}
  8(*------------------------------------------------------------------------------
  9 Delphi Code formatter source code 
 10
 11The Original Code is NoReturnBefore, released May 2003.
 12The Initial Developer of the Original Code is Anthony Steele. 
 13Portions created by Anthony Steele are Copyright (C) 1999-2008 Anthony Steele.
 14All Rights Reserved. 
 15Contributor(s): Anthony Steele. 
 16
 17The contents of this file are subject to the Mozilla Public License Version 1.1
 18(the "License"). you may not use this file except in compliance with the License.
 19You may obtain a copy of the License at http://www.mozilla.org/NPL/
 20
 21Software distributed under the License is distributed on an "AS IS" basis,
 22WITHOUT WARRANTY OF ANY KIND, either express or implied.
 23See the License for the specific language governing rights and limitations 
 24under the License.
 25
 26Alternatively, the contents of this file may be used under the terms of
 27the GNU General Public License Version 2 or later (the "GPL") 
 28See http://www.gnu.org/licenses/gpl.html
 29------------------------------------------------------------------------------*)
 30{*)}
 31
 32{$I JcfGlobal.inc}
 33
 34interface
 35
 36uses SwitchableVisitor;
 37
 38type
 39  TNoReturnBefore = class(TSwitchableVisitor)
 40  private
 41    fbSafeToRemoveReturn: boolean;
 42
 43  protected
 44    function EnabledVisitSourceToken(const pcNode: TObject): Boolean; override;
 45
 46  public
 47    constructor Create; override;
 48
 49    function IsIncludedInSettings: boolean; override;
 50  end;
 51
 52implementation
 53
 54uses SourceToken, TokenUtils, Tokens, ParseTreeNodeType,
 55  JcfSettings, FormatFlags, ParseTreeNode, SettingsTypes;
 56
 57function HasNoReturnBefore(const pt: TSourceToken): boolean;
 58const
 59  NoReturnTokens: TTokenTypeSet    = [ttAssign, ttColon, ttSemiColon, ttPlusAssign, ttMinusAssign, ttTimesAssign, ttFloatDivAssign];
 60  ProcNoReturnWords: TTokenTypeSet = [ttThen, ttDo];
 61var
 62  lcPrev: TParseTreeNode;
 63begin
 64  Result := False;
 65
 66  if pt = nil then
 67    exit;
 68
 69  if pt.HasParentNode(nAsm) then
 70    exit;
 71
 72  { a semicolon should have a return before it if it is the only token in the statement
 73    e.g.
 74    begin
 75     ;
 76    end
 77    }
 78
 79  if (pt.TokenType = ttSemiColon) then
 80  begin
 81    lcPrev := pt.Parent.FirstNodeBefore(pt);
 82    if (lcPrev <> nil) and (lcPrev.NodeType = nStatement) then
 83      exit;
 84  end;
 85
 86  if (pt.TokenType in NoReturnTokens + Operators) then
 87  begin
 88    Result := True;
 89    exit;
 90  end;
 91
 92  { class helper declaration }
 93  if IsClassHelperWords(pt) then
 94  begin
 95    Result := True;
 96    exit;
 97  end;
 98
 99  { no return before then and do  in procedure body }
100  if (pt.TokenType in ProcNoReturnWords) and InStatements(pt) then
101  begin
102    Result := True;
103    exit;
104  end;
105
106  { no return in record def before the record keyword, likewise class & interface
107    be carefull with the word 'class' as it also denotes (static) class fns. }
108  if pt.HasParentNode(nTypeDecl) and (pt.TokenType in StructuredTypeWords) and
109    ( not pt.HasParentNode(nClassVisibility)) then
110  begin
111    Result := True;
112    exit;
113  end;
114
115  if (pt.TokenType = ttCloseSquareBracket) then
116  begin
117    // end of guid in interface
118    if pt.HasParentNode(nInterfaceTypeGuid, 1) then
119    begin
120      Result := True;
121      exit;
122    end;
123
124    if pt.HasParentNode(nAttribute) then
125    begin
126      Result := True;
127      exit;
128    end;
129  end;
130
131
132  // "foo in  Foo.pas, " has return only after the comma
133  if InFilesUses(pt) then
134  begin
135    if (pt.TokenType in [ttComma, ttWord, ttQuotedLiteralString]) or
136      ((pt.TokenType = ttComment) and (pt.CommentStyle in CURLY_COMMENTS)) then
137    begin
138      Result := True;
139      exit;
140    end;
141  end;
142
143  if (pt.CommentStyle = eCompilerDirective) and (CompilerDirectiveLineBreak(pt, True) = eNever) then
144  begin
145    Result := True;
146    exit;
147  end;
148end;
149
150constructor TNoReturnBefore.Create;
151begin
152  inherited;
153  fbSafeToRemoveReturn := True;
154  FormatFlags := FormatFlags + [eRemoveReturn];
155end;
156
157function TNoReturnBefore.EnabledVisitSourceToken(const pcNode: TObject): Boolean;
158var
159  lcSourceToken: TSourceToken;
160  lcNext, lcNextComment: TSourceToken;
161begin
162  Result := False;
163  lcSourceToken := TSourceToken(pcNode);
164
165  // not safe to remove return at a comment like this
166  if (lcSourceToken.TokenType = ttComment) and
167    (lcSourceToken.CommentStyle = eDoubleSlash) then
168    fbSafeToRemoveReturn := False
169  else if (lcSourceToken.TokenType <> ttReturn) then
170    fbSafeToRemoveReturn := True;
171  // safe again after the next return
172
173  if (lcSourceToken.TokenType = ttReturn) and fbSafeToRemoveReturn then
174  begin
175    lcNext := lcSourceToken.NextTokenWithExclusions([ttReturn, ttWhiteSpace]);
176
177    // skip past regular comments
178    while (lcNext <> nil) and (lcNext.TokenType = ttComment) and
179      (lcNext.CommentStyle <> eCompilerDirective) do
180        lcNext := lcNext.NextTokenWithExclusions([ttReturn, ttWhiteSpace]);
181
182    if (lcNext <> nil) and HasNoReturnBefore(lcNext) then
183    begin
184      { must still check for the case of
185          try
186            Statement;
187          except
188            // a comment
189            ;
190          end;
191
192      -- the return before the comment should not be removed
193
194      This does not hold in a program files uses clause or before a compiler directive
195      }
196      lcNextComment := lcSourceToken.NextTokenWithExclusions([ttWhiteSpace, ttReturn]);
197      if (lcNextComment <> nil) and
198        ((lcNextComment.TokenType <> ttComment) or
199         (lcNextComment.CommentStyle = eCompilerDirective) or
200         (InFilesUses(lcNextComment))) then
201        BlankToken(lcSourceToken);
202    end;
203  end;
204end;
205
206function TNoReturnBefore.IsIncludedInSettings: boolean;
207begin
208  Result := FormatSettings.Returns.RemoveBadReturns;
209end;
210
211end.