Fri, 11 Sep 2020 17:28:59 +0200
Class browsers: improved endline detection for the Python, IDL and ProtoBuf source code browsers and the Python module parser.
--- a/eric6/APIs/Python3/eric6.api Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/APIs/Python3/eric6.api Fri Sep 11 17:28:59 2020 +0200 @@ -9179,6 +9179,8 @@ eric6.Utilities.ClassBrowsers.idlclbr._getnext?8 eric6.Utilities.ClassBrowsers.idlclbr._modules?8 eric6.Utilities.ClassBrowsers.idlclbr._normalize?8 +eric6.Utilities.ClassBrowsers.idlclbr.calculateEndline?4(lineno, lines) +eric6.Utilities.ClassBrowsers.idlclbr.calculateMethodEndline?4(lineno, lines) eric6.Utilities.ClassBrowsers.idlclbr.readmodule_ex?4(module, path=None) eric6.Utilities.ClassBrowsers.idlclbr.scan?4(src, file, module) eric6.Utilities.ClassBrowsers.jsclbr.Attribute?1(module, name, file, lineno) @@ -9206,6 +9208,7 @@ eric6.Utilities.ClassBrowsers.protoclbr._getnext?8 eric6.Utilities.ClassBrowsers.protoclbr._modules?8 eric6.Utilities.ClassBrowsers.protoclbr._normalize?8 +eric6.Utilities.ClassBrowsers.protoclbr.calculateEndline?4(lineno, lines) eric6.Utilities.ClassBrowsers.protoclbr.readmodule_ex?4(module, path=None) eric6.Utilities.ClassBrowsers.protoclbr.scan?4(src, file, module) eric6.Utilities.ClassBrowsers.pyclbr.Attribute?1(module, name, file, lineno) @@ -9269,6 +9272,7 @@ eric6.Utilities.ModuleParser.Module.addModule?4(name, module) eric6.Utilities.ModuleParser.Module.addPathToHierarchy?4(path, result, fn) eric6.Utilities.ModuleParser.Module.assembleHierarchy?4(name, classes, path, result) +eric6.Utilities.ModuleParser.Module.calculateEndline?4(lines, indent) eric6.Utilities.ModuleParser.Module.createHierarchy?4() eric6.Utilities.ModuleParser.Module.getFileName?4() eric6.Utilities.ModuleParser.Module.getName?4()
--- a/eric6/Documentation/Help/source.qhp Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Documentation/Help/source.qhp Fri Sep 11 17:28:59 2020 +0200 @@ -9987,6 +9987,7 @@ <keyword name="Module.addModule" id="Module.addModule" ref="eric6.Utilities.ModuleParser.html#Module.addModule" /> <keyword name="Module.addPathToHierarchy" id="Module.addPathToHierarchy" ref="eric6.Utilities.ModuleParser.html#Module.addPathToHierarchy" /> <keyword name="Module.assembleHierarchy" id="Module.assembleHierarchy" ref="eric6.Utilities.ModuleParser.html#Module.assembleHierarchy" /> + <keyword name="Module.calculateEndline" id="Module.calculateEndline" ref="eric6.Utilities.ModuleParser.html#Module.calculateEndline" /> <keyword name="Module.createHierarchy" id="Module.createHierarchy" ref="eric6.Utilities.ModuleParser.html#Module.createHierarchy" /> <keyword name="Module.getFileName" id="Module.getFileName" ref="eric6.Utilities.ModuleParser.html#Module.getFileName" /> <keyword name="Module.getName" id="Module.getName" ref="eric6.Utilities.ModuleParser.html#Module.getName" /> @@ -16978,7 +16979,10 @@ <keyword name="blank_lines" id="blank_lines" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#blank_lines" /> <keyword name="break_after_binary_operator" id="break_after_binary_operator" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#break_after_binary_operator" /> <keyword name="break_before_binary_operator" id="break_before_binary_operator" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.pycodestyle.html#break_before_binary_operator" /> + <keyword name="calculateEndline" id="calculateEndline" ref="eric6.Utilities.ClassBrowsers.idlclbr.html#calculateEndline" /> + <keyword name="calculateEndline" id="calculateEndline" ref="eric6.Utilities.ClassBrowsers.protoclbr.html#calculateEndline" /> <keyword name="calculateEndline" id="calculateEndline" ref="eric6.Utilities.ClassBrowsers.pyclbr.html#calculateEndline" /> + <keyword name="calculateMethodEndline" id="calculateMethodEndline" ref="eric6.Utilities.ClassBrowsers.idlclbr.html#calculateMethodEndline" /> <keyword name="certificateValidation (Module)" id="certificateValidation (Module)" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.certificateValidation.html" /> <keyword name="changeRememberedMaster" id="changeRememberedMaster" ref="eric6.Utilities.crypto.__init__.html#changeRememberedMaster" /> <keyword name="checkAssertUsed" id="checkAssertUsed" ref="eric6.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.assert.html#checkAssertUsed" />
--- a/eric6/Documentation/Source/eric6.Utilities.ClassBrowsers.idlclbr.html Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Documentation/Source/eric6.Utilities.ClassBrowsers.idlclbr.html Fri Sep 11 17:28:59 2020 +0200 @@ -69,6 +69,14 @@ <table> <tr> +<td><a href="#calculateEndline">calculateEndline</a></td> +<td>Function to calculate the end line.</td> +</tr> +<tr> +<td><a href="#calculateMethodEndline">calculateMethodEndline</a></td> +<td>Function to calculate the end line.</td> +</tr> +<tr> <td><a href="#readmodule_ex">readmodule_ex</a></td> <td>Read a CORBA IDL file and return a dictionary of classes, functions and modules.</td> </tr> @@ -383,6 +391,72 @@ <div align="right"><a href="#top">Up</a></div> <hr /> <hr /> +<a NAME="calculateEndline" ID="calculateEndline"></a> +<h2>calculateEndline</h2> +<b>calculateEndline</b>(<i>lineno, lines</i>) + +<p> + Function to calculate the end line. +</p> +<dl> + +<dt><i>lineno</i> (int)</dt> +<dd> +line number to start at (one based) +</dd> +<dt><i>lines</i> (list of str)</dt> +<dd> +list of source lines +</dd> +</dl> +<dl> +<dt>Returns:</dt> +<dd> +end line (one based) +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +int +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="calculateMethodEndline" ID="calculateMethodEndline"></a> +<h2>calculateMethodEndline</h2> +<b>calculateMethodEndline</b>(<i>lineno, lines</i>) + +<p> + Function to calculate the end line. +</p> +<dl> + +<dt><i>lineno</i> (int)</dt> +<dd> +line number to start at (one based) +</dd> +<dt><i>lines</i> (list of str)</dt> +<dd> +list of source lines +</dd> +</dl> +<dl> +<dt>Returns:</dt> +<dd> +end line (one based) +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +int +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> <a NAME="readmodule_ex" ID="readmodule_ex"></a> <h2>readmodule_ex</h2> <b>readmodule_ex</b>(<i>module, path=None</i>)
--- a/eric6/Documentation/Source/eric6.Utilities.ClassBrowsers.protoclbr.html Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Documentation/Source/eric6.Utilities.ClassBrowsers.protoclbr.html Fri Sep 11 17:28:59 2020 +0200 @@ -64,6 +64,10 @@ <table> <tr> +<td><a href="#calculateEndline">calculateEndline</a></td> +<td>Function to calculate the end line.</td> +</tr> +<tr> <td><a href="#readmodule_ex">readmodule_ex</a></td> <td>Read a ProtoBuf protocol file and return a dictionary of messages, enums, services and rpc methods.</td> </tr> @@ -369,6 +373,39 @@ <div align="right"><a href="#top">Up</a></div> <hr /> <hr /> +<a NAME="calculateEndline" ID="calculateEndline"></a> +<h2>calculateEndline</h2> +<b>calculateEndline</b>(<i>lineno, lines</i>) + +<p> + Function to calculate the end line. +</p> +<dl> + +<dt><i>lineno</i> (int)</dt> +<dd> +line number to start at (one based) +</dd> +<dt><i>lines</i> (list of str)</dt> +<dd> +list of source lines +</dd> +</dl> +<dl> +<dt>Returns:</dt> +<dd> +end line (one based) +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +int +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> <a NAME="readmodule_ex" ID="readmodule_ex"></a> <h2>readmodule_ex</h2> <b>readmodule_ex</b>(<i>module, path=None</i>)
--- a/eric6/Documentation/Source/eric6.Utilities.ClassBrowsers.pyclbr.html Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Documentation/Source/eric6.Utilities.ClassBrowsers.pyclbr.html Fri Sep 11 17:28:59 2020 +0200 @@ -637,7 +637,7 @@ <dt><i>lineno</i> (int)</dt> <dd> -line number to start at +line number to start at (one based) </dd> <dt><i>lines</i> (list of str)</dt> <dd> @@ -651,7 +651,7 @@ <dl> <dt>Returns:</dt> <dd> -end line of the class/method/function +end line of the class/method/function (one based) </dd> </dl> <dl>
--- a/eric6/Documentation/Source/eric6.Utilities.ModuleParser.html Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Documentation/Source/eric6.Utilities.ModuleParser.html Fri Sep 11 17:28:59 2020 +0200 @@ -581,6 +581,10 @@ <td>Public method to assemble the inheritance hierarchy.</td> </tr> <tr> +<td><a href="#Module.calculateEndline">calculateEndline</a></td> +<td>Function to calculate the end line of a class or method/function.</td> +</tr> +<tr> <td><a href="#Module.createHierarchy">createHierarchy</a></td> <td>Public method to build the inheritance hierarchy for all classes of this module.</td> </tr> @@ -816,6 +820,40 @@ The resultant hierarchy </dd> </dl> +<a NAME="Module.calculateEndline" ID="Module.calculateEndline"></a> +<h4>Module.calculateEndline</h4> +<b>calculateEndline</b>(<i>lines, indent</i>) + +<p> + Function to calculate the end line of a class or method/function. +</p> +<dl> + +<dt><i>lineno</i> (int)</dt> +<dd> +line number to start at (one based) +</dd> +<dt><i>lines</i> (list of str)</dt> +<dd> +list of source lines +</dd> +<dt><i>indent</i> (int)</dt> +<dd> +indent length the class/method/function definition +</dd> +</dl> +<dl> +<dt>Returns:</dt> +<dd> +end line of the class/method/function (one based) +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +int +</dd> +</dl> <a NAME="Module.createHierarchy" ID="Module.createHierarchy"></a> <h4>Module.createHierarchy</h4> <b>createHierarchy</b>(<i></i>)
--- a/eric6/Utilities/ClassBrowsers/idlclbr.py Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Utilities/ClassBrowsers/idlclbr.py Fri Sep 11 17:28:59 2020 +0200 @@ -252,8 +252,58 @@ @return dictionary containing the extracted data @rtype dict """ + def calculateEndline(lineno, lines): + """ + Function to calculate the end line. + + @param lineno line number to start at (one based) + @type int + @param lines list of source lines + @type list of str + @return end line (one based) + @rtype int + """ + # convert lineno to be zero based + lineno -= 1 + # 1. search for opening brace '{' + while lineno < len(lines) and not "{" in lines[lineno]: + lineno += 1 + depth = lines[lineno].count("{") - lines[lineno].count("}") + # 2. search for ending line, i.e. matching closing brace '}' + while depth > 0 and lineno < len(lines) - 1: + lineno += 1 + depth += lines[lineno].count("{") - lines[lineno].count("}") + if depth == 0: + # found a matching brace + return lineno + 1 + else: + # nothing found + return -1 + + def calculateMethodEndline(lineno, lines): + """ + Function to calculate the end line. + + @param lineno line number to start at (one based) + @type int + @param lines list of source lines + @type list of str + @return end line (one based) + @rtype int + """ + # convert lineno to be zero based + lineno -= 1 + while lineno < len(lines) and not ";" in lines[lineno]: + lineno += 1 + if ";" in lines[lineno]: + # found an end indicator, i.e. ';' + return lineno + 1 + else: + return -1 + # convert eol markers the Python style src = src.replace("\r\n", "\n").replace("\r", "\n") + srcLines = src.splitlines() dictionary = {} dict_counts = {} @@ -262,8 +312,6 @@ indent = 0 lineno, last_lineno_pos = 1, 0 - lastGlobalEntry = None - cur_obj = None i = 0 while True: m = _getnext(src, i) @@ -283,9 +331,6 @@ last_lineno_pos = start # close all interfaces/modules indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] if classstack: # it's an interface/module method @@ -312,13 +357,9 @@ else: dict_counts[meth_name] = 0 dictionary[meth_name] = f - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = f - if cur_obj and isinstance(cur_obj, Function): - cur_obj.setEndLine(lineno - 1) - cur_obj = f + if f: + endline = calculateMethodEndline(lineno, srcLines) + f.setEndLine(endline) classstack.append((f, thisindent)) # Marker for nested fns elif m.start("String") >= 0: @@ -333,9 +374,6 @@ indent += 1 # close all interfaces/modules indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] lineno = lineno + src.count('\n', last_lineno_pos, start) last_lineno_pos = start @@ -348,18 +386,13 @@ # remember this interface cur_class = Interface(module, class_name, inherit, file, lineno) + endline = calculateEndline(lineno, srcLines) + cur_class.setEndLine(endline) if not classstack: dictionary[class_name] = cur_class else: cls = classstack[-1][0] cls._addclass(class_name, cur_class) - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = cur_class - if cur_obj and isinstance(cur_obj, Function): - cur_obj.setEndLine(lineno - 1) - cur_obj = cur_class classstack.append((cur_class, thisindent)) elif m.start("Module") >= 0: @@ -368,23 +401,16 @@ indent += 1 # close all interfaces/modules indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] lineno = lineno + src.count('\n', last_lineno_pos, start) last_lineno_pos = start module_name = m.group("ModuleName") # remember this module cur_class = Module(module, module_name, file, lineno) + endline = calculateEndline(lineno, srcLines) + cur_class.setEndLine(endline) if not classstack: dictionary[module_name] = cur_class - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = cur_class - if cur_obj and isinstance(cur_obj, Function): - cur_obj.setEndLine(lineno - 1) - cur_obj = cur_class classstack.append((cur_class, thisindent)) elif m.start("Attribute") >= 0: @@ -407,9 +433,6 @@ break else: index -= 1 - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = None elif m.start("Begin") >= 0: # a begin of a block we are not interested in
--- a/eric6/Utilities/ClassBrowsers/protoclbr.py Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Utilities/ClassBrowsers/protoclbr.py Fri Sep 11 17:28:59 2020 +0200 @@ -243,8 +243,37 @@ @return dictionary containing the extracted data @rtype dict """ + def calculateEndline(lineno, lines): + """ + Function to calculate the end line. + + @param lineno line number to start at (one based) + @type int + @param lines list of source lines + @type list of str + @return end line (one based) + @rtype int + """ + # convert lineno to be zero based + lineno -= 1 + # 1. search for opening brace '{' + while lineno < len(lines) and not "{" in lines[lineno]: + lineno += 1 + depth = lines[lineno].count("{") - lines[lineno].count("}") + # 2. search for ending line, i.e. matching closing brace '}' + while depth > 0 and lineno < len(lines) - 1: + lineno += 1 + depth += lines[lineno].count("{") - lines[lineno].count("}") + if depth == 0: + # found a matching brace + return lineno + 1 + else: + # nothing found + return -1 + # convert eol markers the Python style src = src.replace("\r\n", "\n").replace("\r", "\n") + srcLines = src.splitlines() dictionary = {} @@ -252,8 +281,6 @@ indent = 0 lineno, last_lineno_pos = 1, 0 - lastGlobalEntry = None - cur_obj = None i = 0 while True: m = _getnext(src, i) @@ -277,9 +304,6 @@ last_lineno_pos = start # close all interfaces/modules indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] if classstack: # it's an interface/module method @@ -295,13 +319,9 @@ else: # the file is incorrect, ignore the entry continue - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = f - if cur_obj and isinstance(cur_obj, ServiceMethod): - cur_obj.setEndLine(lineno - 1) - cur_obj = f + if f: + endline = calculateEndline(lineno, srcLines) + f.setEndLine(endline) classstack.append((f, thisindent)) # Marker for nested fns elif m.start("String") >= 0: @@ -319,22 +339,16 @@ message_name = m.group("MessageName") # close all messages/services indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] # remember this message cur_class = Message(module, message_name, file, lineno) + endline = calculateEndline(lineno, srcLines) + cur_class.setEndLine(endline) if not classstack: dictionary[message_name] = cur_class else: msg = classstack[-1][0] msg._addclass(message_name, cur_class) - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = cur_class - cur_obj = cur_class classstack.append((cur_class, thisindent)) elif m.start("Enum") >= 0: @@ -343,25 +357,19 @@ indent += 1 # close all messages/services indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] lineno = lineno + src.count('\n', last_lineno_pos, start) last_lineno_pos = start enum_name = m.group("EnumName") # remember this Enum cur_class = Enum(module, enum_name, file, lineno) + endline = calculateEndline(lineno, srcLines) + cur_class.setEndLine(endline) if not classstack: dictionary[enum_name] = cur_class else: enum = classstack[-1][0] enum._addclass(enum_name, cur_class) - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = cur_class - cur_obj = cur_class classstack.append((cur_class, thisindent)) elif m.start("Service") >= 0: @@ -370,25 +378,19 @@ indent += 1 # close all messages/services indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] lineno = lineno + src.count('\n', last_lineno_pos, start) last_lineno_pos = start service_name = m.group("ServiceName") # remember this Service cur_class = Service(module, service_name, file, lineno) + endline = calculateEndline(lineno, srcLines) + cur_class.setEndLine(endline) if not classstack: dictionary[service_name] = cur_class else: service = classstack[-1][0] service._addclass(service_name, cur_class) - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = cur_class - cur_obj = cur_class classstack.append((cur_class, thisindent)) elif m.start("Begin") >= 0:
--- a/eric6/Utilities/ClassBrowsers/pyclbr.py Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Utilities/ClassBrowsers/pyclbr.py Fri Sep 11 17:28:59 2020 +0200 @@ -13,11 +13,11 @@ import sys import re +from functools import reduce import Utilities import Utilities.ClassBrowsers as ClassBrowsers from . import ClbrBaseClasses -from functools import reduce TABWIDTH = 4 @@ -404,13 +404,13 @@ """ Function to calculate the end line of a class or method/function. - @param lineno line number to start at + @param lineno line number to start at (one based) @type int @param lines list of source lines @type list of str @param indent indent length the class/method/function definition @type int - @return end line of the class/method/function + @return end line of the class/method/function (one based) @rtype int """ # start with zero based line after start line @@ -440,7 +440,6 @@ deltaindentcalculated = 0 lineno, last_lineno_pos = 1, 0 - cur_obj = None i = 0 modifierType = ClbrBaseClasses.Function.General modifierIndent = -1 @@ -494,9 +493,6 @@ deltaindentcalculated = 0 # close all classes indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] if classstack: # it's a class method @@ -507,6 +503,8 @@ file, lineno, meth_sig, annotation=meth_ret, modifierType=modifier) cur_class._addmethod(meth_name, f) + else: + f = None else: # it's a function f = Function(module, meth_name, @@ -519,12 +517,10 @@ else: dict_counts[meth_name] = 0 dictionary[meth_name] = f - endlineno = calculateEndline(lineno, srcLines, thisindent) - f.setEndLine(endlineno) - if cur_obj and isinstance(cur_obj, Function): - cur_obj.setEndLine(lineno - 1) - cur_obj = f - classstack.append((f, thisindent)) # Marker for nested fns + if f: + endlineno = calculateEndline(lineno, srcLines, thisindent) + f.setEndLine(endlineno) + classstack.append((f, thisindent)) # Marker for nested fns # reset the modifier settings modifierType = ClbrBaseClasses.Function.General @@ -538,9 +534,6 @@ thisindent = _indent(m.group("ClassIndent")) # close all classes indented at least as much while classstack and classstack[-1][1] >= thisindent: - if classstack[-1][0] is not None: - # record the end line - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] lineno = lineno + src.count('\n', last_lineno_pos, start) last_lineno_pos = start
--- a/eric6/Utilities/ModuleParser.py Wed Sep 09 18:07:21 2020 +0200 +++ b/eric6/Utilities/ModuleParser.py Fri Sep 11 17:28:59 2020 +0200 @@ -524,8 +524,35 @@ @param src the source text to be scanned (string) """ + def calculateEndline(lineno, lines, indent): + """ + Function to calculate the end line of a class or method/function. + + @param lineno line number to start at (one based) + @type int + @param lines list of source lines + @type list of str + @param indent indent length the class/method/function definition + @type int + @return end line of the class/method/function (one based) + @rtype int + """ + # start with zero based line after start line + while lineno < len(lines): + line = lines[lineno] + if line.strip(): + # line contains some text + lineIndent = _indent(line.replace(line.lstrip(), "")) + if lineIndent <= indent: + return lineno + lineno += 1 + + # nothing found + return -1 + + srcLines = src.splitlines() + lineno, last_lineno_pos = 1, 0 - lastGlobalEntry = None classstack = [] # stack of (class, indent) pairs conditionalsstack = [] # stack of indents of conditional defines deltastack = [] @@ -596,12 +623,6 @@ deltaindentcalculated = 0 # close all classes indented at least as much while classstack and classstack[-1][1] >= thisindent: - if ( - classstack[-1][0] is not None and - isinstance(classstack[-1][0], (Class, Function)) - ): - # record the end line of this class or function - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] if classstack: csi = -1 @@ -636,12 +657,8 @@ annotation=meth_ret) self.__py_setVisibility(f) self.addFunction(meth_name, f) - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = f - if cur_obj and isinstance(cur_obj, Function): - cur_obj.setEndLine(lineno - 1) + endlineno = calculateEndline(lineno, srcLines, thisindent) + f.setEndLine(endlineno) cur_obj = f classstack.append((None, thisindent)) # Marker for nested fns @@ -693,12 +710,6 @@ last_lineno_pos = start # close all classes indented at least as much while classstack and classstack[-1][1] >= thisindent: - if ( - classstack[-1][0] is not None and - isinstance(classstack[-1][0], (Class, Function)) - ): - # record the end line of this class or function - classstack[-1][0].setEndLine(lineno - 1) del classstack[-1] class_name = m.group("ClassName") inherit = m.group("ClassSupers") @@ -730,13 +741,11 @@ cur_class = Class(self.name, class_name, inherit, self.file, lineno) self.__py_setVisibility(cur_class) + endlineno = calculateEndline(lineno, srcLines, thisindent) + cur_class.setEndLine(endlineno) cur_obj = cur_class - # add nested classes to the module self.addClass(class_name, cur_class) - if not classstack: - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = cur_class + # add nested classes to the module classstack.append((cur_class, thisindent)) elif m.start("Attribute") >= 0: @@ -773,9 +782,6 @@ isSignal=isSignal) self.__py_setVisibility(attr) self.addGlobal(variable_name, attr) - if lastGlobalEntry: - lastGlobalEntry.setEndLine(lineno - 1) - lastGlobalEntry = None else: index = -1 while index >= -len(classstack):