@@ 5168-5304 (lines=137) @@ | ||
5165 | return False |
|
5166 | ||
5167 | ||
5168 | def CheckForNonConstReference(filename, clean_lines, linenum, |
|
5169 | nesting_state, error): |
|
5170 | """Check for non-const references. |
|
5171 | ||
5172 | Separate from CheckLanguage since it scans backwards from current |
|
5173 | line, instead of scanning forward. |
|
5174 | ||
5175 | Args: |
|
5176 | filename: The name of the current file. |
|
5177 | clean_lines: A CleansedLines instance containing the file. |
|
5178 | linenum: The number of the line to check. |
|
5179 | nesting_state: A NestingState instance which maintains information about |
|
5180 | the current stack of nested blocks being parsed. |
|
5181 | error: The function to call with any errors found. |
|
5182 | """ |
|
5183 | # Do nothing if there is no '&' on current line. |
|
5184 | line = clean_lines.elided[linenum] |
|
5185 | if '&' not in line: |
|
5186 | return |
|
5187 | ||
5188 | # If a function is inherited, current function doesn't have much of |
|
5189 | # a choice, so any non-const references should not be blamed on |
|
5190 | # derived function. |
|
5191 | if IsDerivedFunction(clean_lines, linenum): |
|
5192 | return |
|
5193 | ||
5194 | # Don't warn on out-of-line method definitions, as we would warn on the |
|
5195 | # in-line declaration, if it isn't marked with 'override'. |
|
5196 | if IsOutOfLineMethodDefinition(clean_lines, linenum): |
|
5197 | return |
|
5198 | ||
5199 | # Long type names may be broken across multiple lines, usually in one |
|
5200 | # of these forms: |
|
5201 | # LongType |
|
5202 | # ::LongTypeContinued &identifier |
|
5203 | # LongType:: |
|
5204 | # LongTypeContinued &identifier |
|
5205 | # LongType< |
|
5206 | # ...>::LongTypeContinued &identifier |
|
5207 | # |
|
5208 | # If we detected a type split across two lines, join the previous |
|
5209 | # line to current line so that we can match const references |
|
5210 | # accordingly. |
|
5211 | # |
|
5212 | # Note that this only scans back one line, since scanning back |
|
5213 | # arbitrary number of lines would be expensive. If you have a type |
|
5214 | # that spans more than 2 lines, please use a typedef. |
|
5215 | if linenum > 1: |
|
5216 | previous = None |
|
5217 | if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line): |
|
5218 | # previous_line\n + ::current_line |
|
5219 | previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$', |
|
5220 | clean_lines.elided[linenum - 1]) |
|
5221 | elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line): |
|
5222 | # previous_line::\n + current_line |
|
5223 | previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$', |
|
5224 | clean_lines.elided[linenum - 1]) |
|
5225 | if previous: |
|
5226 | line = previous.group(1) + line.lstrip() |
|
5227 | else: |
|
5228 | # Check for templated parameter that is split across multiple lines |
|
5229 | endpos = line.rfind('>') |
|
5230 | if endpos > -1: |
|
5231 | (_, startline, startpos) = ReverseCloseExpression( |
|
5232 | clean_lines, linenum, endpos) |
|
5233 | if startpos > -1 and startline < linenum: |
|
5234 | # Found the matching < on an earlier line, collect all |
|
5235 | # pieces up to current line. |
|
5236 | line = '' |
|
5237 | for i in xrange(startline, linenum + 1): |
|
5238 | line += clean_lines.elided[i].strip() |
|
5239 | ||
5240 | # Check for non-const references in function parameters. A single '&' may |
|
5241 | # found in the following places: |
|
5242 | # inside expression: binary & for bitwise AND |
|
5243 | # inside expression: unary & for taking the address of something |
|
5244 | # inside declarators: reference parameter |
|
5245 | # We will exclude the first two cases by checking that we are not inside a |
|
5246 | # function body, including one that was just introduced by a trailing '{'. |
|
5247 | # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. |
|
5248 | if (nesting_state.previous_stack_top and |
|
5249 | not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or |
|
5250 | isinstance(nesting_state.previous_stack_top, _NamespaceInfo))): |
|
5251 | # Not at toplevel, not within a class, and not within a namespace |
|
5252 | return |
|
5253 | ||
5254 | # Avoid initializer lists. We only need to scan back from the |
|
5255 | # current line for something that starts with ':'. |
|
5256 | # |
|
5257 | # We don't need to check the current line, since the '&' would |
|
5258 | # appear inside the second set of parentheses on the current line as |
|
5259 | # opposed to the first set. |
|
5260 | if linenum > 0: |
|
5261 | for i in xrange(linenum - 1, max(0, linenum - 10), -1): |
|
5262 | previous_line = clean_lines.elided[i] |
|
5263 | if not Search(r'[),]\s*$', previous_line): |
|
5264 | break |
|
5265 | if Match(r'^\s*:\s+\S', previous_line): |
|
5266 | return |
|
5267 | ||
5268 | # Avoid preprocessors |
|
5269 | if Search(r'\\\s*$', line): |
|
5270 | return |
|
5271 | ||
5272 | # Avoid constructor initializer lists |
|
5273 | if IsInitializerList(clean_lines, linenum): |
|
5274 | return |
|
5275 | ||
5276 | # We allow non-const references in a few standard places, like functions |
|
5277 | # called "swap()" or iostream operators like "<<" or ">>". Do not check |
|
5278 | # those function parameters. |
|
5279 | # |
|
5280 | # We also accept & in static_assert, which looks like a function but |
|
5281 | # it's actually a declaration expression. |
|
5282 | whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|' |
|
5283 | r'operator\s*[<>][<>]|' |
|
5284 | r'static_assert|COMPILE_ASSERT' |
|
5285 | r')\s*\(') |
|
5286 | if Search(whitelisted_functions, line): |
|
5287 | return |
|
5288 | elif not Search(r'\S+\([^)]*$', line): |
|
5289 | # Don't see a whitelisted function on this line. Actually we |
|
5290 | # didn't see any function name on this line, so this is likely a |
|
5291 | # multi-line parameter list. Try a bit harder to catch this case. |
|
5292 | for i in xrange(2): |
|
5293 | if (linenum > i and |
|
5294 | Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])): |
|
5295 | return |
|
5296 | ||
5297 | decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body |
|
5298 | for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls): |
|
5299 | if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and |
|
5300 | not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)): |
|
5301 | error(filename, linenum, 'runtime/references', 2, |
|
5302 | 'Is this a non-const reference? ' |
|
5303 | 'If so, make const or use a pointer: ' + |
|
5304 | ReplaceAll(' *<', '<', parameter)) |
|
5305 | ||
5306 | ||
5307 | def CheckCasts(filename, clean_lines, linenum, error): |
@@ 5168-5304 (lines=137) @@ | ||
5165 | return False |
|
5166 | ||
5167 | ||
5168 | def CheckForNonConstReference(filename, clean_lines, linenum, |
|
5169 | nesting_state, error): |
|
5170 | """Check for non-const references. |
|
5171 | ||
5172 | Separate from CheckLanguage since it scans backwards from current |
|
5173 | line, instead of scanning forward. |
|
5174 | ||
5175 | Args: |
|
5176 | filename: The name of the current file. |
|
5177 | clean_lines: A CleansedLines instance containing the file. |
|
5178 | linenum: The number of the line to check. |
|
5179 | nesting_state: A NestingState instance which maintains information about |
|
5180 | the current stack of nested blocks being parsed. |
|
5181 | error: The function to call with any errors found. |
|
5182 | """ |
|
5183 | # Do nothing if there is no '&' on current line. |
|
5184 | line = clean_lines.elided[linenum] |
|
5185 | if '&' not in line: |
|
5186 | return |
|
5187 | ||
5188 | # If a function is inherited, current function doesn't have much of |
|
5189 | # a choice, so any non-const references should not be blamed on |
|
5190 | # derived function. |
|
5191 | if IsDerivedFunction(clean_lines, linenum): |
|
5192 | return |
|
5193 | ||
5194 | # Don't warn on out-of-line method definitions, as we would warn on the |
|
5195 | # in-line declaration, if it isn't marked with 'override'. |
|
5196 | if IsOutOfLineMethodDefinition(clean_lines, linenum): |
|
5197 | return |
|
5198 | ||
5199 | # Long type names may be broken across multiple lines, usually in one |
|
5200 | # of these forms: |
|
5201 | # LongType |
|
5202 | # ::LongTypeContinued &identifier |
|
5203 | # LongType:: |
|
5204 | # LongTypeContinued &identifier |
|
5205 | # LongType< |
|
5206 | # ...>::LongTypeContinued &identifier |
|
5207 | # |
|
5208 | # If we detected a type split across two lines, join the previous |
|
5209 | # line to current line so that we can match const references |
|
5210 | # accordingly. |
|
5211 | # |
|
5212 | # Note that this only scans back one line, since scanning back |
|
5213 | # arbitrary number of lines would be expensive. If you have a type |
|
5214 | # that spans more than 2 lines, please use a typedef. |
|
5215 | if linenum > 1: |
|
5216 | previous = None |
|
5217 | if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line): |
|
5218 | # previous_line\n + ::current_line |
|
5219 | previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$', |
|
5220 | clean_lines.elided[linenum - 1]) |
|
5221 | elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line): |
|
5222 | # previous_line::\n + current_line |
|
5223 | previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$', |
|
5224 | clean_lines.elided[linenum - 1]) |
|
5225 | if previous: |
|
5226 | line = previous.group(1) + line.lstrip() |
|
5227 | else: |
|
5228 | # Check for templated parameter that is split across multiple lines |
|
5229 | endpos = line.rfind('>') |
|
5230 | if endpos > -1: |
|
5231 | (_, startline, startpos) = ReverseCloseExpression( |
|
5232 | clean_lines, linenum, endpos) |
|
5233 | if startpos > -1 and startline < linenum: |
|
5234 | # Found the matching < on an earlier line, collect all |
|
5235 | # pieces up to current line. |
|
5236 | line = '' |
|
5237 | for i in xrange(startline, linenum + 1): |
|
5238 | line += clean_lines.elided[i].strip() |
|
5239 | ||
5240 | # Check for non-const references in function parameters. A single '&' may |
|
5241 | # found in the following places: |
|
5242 | # inside expression: binary & for bitwise AND |
|
5243 | # inside expression: unary & for taking the address of something |
|
5244 | # inside declarators: reference parameter |
|
5245 | # We will exclude the first two cases by checking that we are not inside a |
|
5246 | # function body, including one that was just introduced by a trailing '{'. |
|
5247 | # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. |
|
5248 | if (nesting_state.previous_stack_top and |
|
5249 | not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or |
|
5250 | isinstance(nesting_state.previous_stack_top, _NamespaceInfo))): |
|
5251 | # Not at toplevel, not within a class, and not within a namespace |
|
5252 | return |
|
5253 | ||
5254 | # Avoid initializer lists. We only need to scan back from the |
|
5255 | # current line for something that starts with ':'. |
|
5256 | # |
|
5257 | # We don't need to check the current line, since the '&' would |
|
5258 | # appear inside the second set of parentheses on the current line as |
|
5259 | # opposed to the first set. |
|
5260 | if linenum > 0: |
|
5261 | for i in xrange(linenum - 1, max(0, linenum - 10), -1): |
|
5262 | previous_line = clean_lines.elided[i] |
|
5263 | if not Search(r'[),]\s*$', previous_line): |
|
5264 | break |
|
5265 | if Match(r'^\s*:\s+\S', previous_line): |
|
5266 | return |
|
5267 | ||
5268 | # Avoid preprocessors |
|
5269 | if Search(r'\\\s*$', line): |
|
5270 | return |
|
5271 | ||
5272 | # Avoid constructor initializer lists |
|
5273 | if IsInitializerList(clean_lines, linenum): |
|
5274 | return |
|
5275 | ||
5276 | # We allow non-const references in a few standard places, like functions |
|
5277 | # called "swap()" or iostream operators like "<<" or ">>". Do not check |
|
5278 | # those function parameters. |
|
5279 | # |
|
5280 | # We also accept & in static_assert, which looks like a function but |
|
5281 | # it's actually a declaration expression. |
|
5282 | whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|' |
|
5283 | r'operator\s*[<>][<>]|' |
|
5284 | r'static_assert|COMPILE_ASSERT' |
|
5285 | r')\s*\(') |
|
5286 | if Search(whitelisted_functions, line): |
|
5287 | return |
|
5288 | elif not Search(r'\S+\([^)]*$', line): |
|
5289 | # Don't see a whitelisted function on this line. Actually we |
|
5290 | # didn't see any function name on this line, so this is likely a |
|
5291 | # multi-line parameter list. Try a bit harder to catch this case. |
|
5292 | for i in xrange(2): |
|
5293 | if (linenum > i and |
|
5294 | Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])): |
|
5295 | return |
|
5296 | ||
5297 | decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body |
|
5298 | for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls): |
|
5299 | if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and |
|
5300 | not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)): |
|
5301 | error(filename, linenum, 'runtime/references', 2, |
|
5302 | 'Is this a non-const reference? ' |
|
5303 | 'If so, make const or use a pointer: ' + |
|
5304 | ReplaceAll(' *<', '<', parameter)) |
|
5305 | ||
5306 | ||
5307 | def CheckCasts(filename, clean_lines, linenum, error): |