/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

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