Index: third_party/closure_linter/closure_linter/indentation.py |
diff --git a/third_party/closure_linter/closure_linter/indentation.py b/third_party/closure_linter/closure_linter/indentation.py |
index 0abb25b149a0111aa8be38ff1eee7534a708bf43..d48ad2b862c43acfb4fbd1c7c5b5b329ecfd4327 100755 |
--- a/third_party/closure_linter/closure_linter/indentation.py |
+++ b/third_party/closure_linter/closure_linter/indentation.py |
@@ -181,21 +181,11 @@ class IndentationRules(object): |
elif token_type == Type.KEYWORD and token.string in ('case', 'default'): |
self._Add(self._PopTo(Type.START_BLOCK)) |
- elif is_first and token.string == '.': |
- # This token should have been on the previous line, so treat it as if it |
- # was there. |
- info = TokenInfo(token) |
- info.line_number = token.line_number - 1 |
- self._Add(info) |
- |
elif token_type == Type.SEMICOLON: |
self._PopTransient() |
- not_binary_operator = (token_type != Type.OPERATOR or |
- token.metadata.IsUnaryOperator()) |
- not_dot = token.string != '.' |
- if is_first and not_binary_operator and not_dot and token.type not in ( |
- Type.COMMENT, Type.DOC_PREFIX, Type.STRING_TEXT): |
+ if (is_first and |
+ token_type not in (Type.COMMENT, Type.DOC_PREFIX, Type.STRING_TEXT)): |
if flags.FLAGS.debug_indentation: |
print 'Line #%d: stack %r' % (token.line_number, stack) |
@@ -222,8 +212,7 @@ class IndentationRules(object): |
indentation_errors.append([ |
errors.WRONG_INDENTATION, |
'Wrong indentation: expected any of {%s} but got %d' % ( |
- ', '.join( |
- ['%d' % x for x in expected]), actual), |
+ ', '.join('%d' % x for x in expected if x < 80), actual), |
token, |
Position(actual, expected[0])]) |
self._start_index_offset[token.line_number] = expected[0] - actual |
@@ -254,6 +243,9 @@ class IndentationRules(object): |
# Add some tokens only if they appear at the end of the line. |
is_last = self._IsLastCodeInLine(token) |
if is_last: |
+ next_code_token = tokenutil.GetNextCodeToken(token) |
+ # Increase required indentation if this is an overlong wrapped statement |
+ # ending in an operator. |
if token_type == Type.OPERATOR: |
if token.string == ':': |
if stack and stack[-1].token.string == '?': |
@@ -274,7 +266,6 @@ class IndentationRules(object): |
# When in an object literal, acts as operator indicating line |
# continuations. |
self._Add(TokenInfo(token)) |
- pass |
else: |
# ':' might also be a statement label, no effect on indentation in |
# this case. |
@@ -288,9 +279,10 @@ class IndentationRules(object): |
self._Add(TokenInfo(token)) |
elif token.metadata.context.type != Context.PARAMETERS: |
self._PopTransient() |
- |
- elif (token.string.endswith('.') |
- and token_type in (Type.IDENTIFIER, Type.NORMAL)): |
+ # Increase required indentation if this is the end of a statement that's |
+ # continued with an operator on the next line (e.g. the '.'). |
+ elif (next_code_token and next_code_token.type == Type.OPERATOR and |
+ not next_code_token.metadata.IsUnaryOperator()): |
self._Add(TokenInfo(token)) |
elif token_type == Type.PARAMETERS and token.string.endswith(','): |
# Parameter lists. |
@@ -376,6 +368,13 @@ class IndentationRules(object): |
override_is_hard_stop = (token_info.overridden_by and |
self._IsHardStop( |
token_info.overridden_by.token)) |
+ if token.type == Type.START_PAREN and token.previous: |
+ # For someFunction(...) we allow to indent at the beginning of the |
+ # identifier +4 |
+ prev = token.previous |
+ if (prev.type == Type.IDENTIFIER and |
+ prev.line_number == token.line_number): |
+ hard_stops.add(prev.start_index + 4) |
if not override_is_hard_stop: |
start_index = token.start_index |
if token.line_number in self._start_index_offset: |
@@ -457,6 +456,31 @@ class IndentationRules(object): |
if token.type not in Type.NON_CODE_TYPES: |
return False |
+ def _AllFunctionPropertyAssignTokens(self, start_token, end_token): |
+ """Checks if tokens are (likely) a valid function property assignment. |
+ |
+ Args: |
+ start_token: Start of the token range. |
+ end_token: End of the token range. |
+ |
+ Returns: |
+ True if all tokens between start_token and end_token are legal tokens |
+ within a function declaration and assignment into a property. |
+ """ |
+ for token in tokenutil.GetTokenRange(start_token, end_token): |
+ fn_decl_tokens = (Type.FUNCTION_DECLARATION, |
+ Type.PARAMETERS, |
+ Type.START_PARAMETERS, |
+ Type.END_PARAMETERS, |
+ Type.END_PAREN) |
+ if (token.type not in fn_decl_tokens and |
+ token.IsCode() and |
+ not tokenutil.IsIdentifierOrDot(token) and |
+ not token.IsAssignment() and |
+ not (token.type == Type.OPERATOR and token.string == ',')): |
+ return False |
+ return True |
+ |
def _Add(self, token_info): |
"""Adds the given token info to the stack. |
@@ -468,11 +492,35 @@ class IndentationRules(object): |
return |
if token_info.is_block or token_info.token.type == Type.START_PAREN: |
- token_info.overridden_by = ( |
- tokenutil.GoogScopeOrNoneFromStartBlock(token_info.token)) |
- index = 1 |
- while index <= len(self._stack): |
- stack_info = self._stack[-index] |
+ scope_token = tokenutil.GoogScopeOrNoneFromStartBlock(token_info.token) |
+ token_info.overridden_by = TokenInfo(scope_token) if scope_token else None |
+ |
+ if (token_info.token.type == Type.START_BLOCK and |
+ token_info.token.metadata.context.type == Context.BLOCK): |
+ # Handle function() {} assignments: their block contents get special |
+ # treatment and are allowed to just indent by two whitespace. |
+ # For example |
+ # long.long.name = function( |
+ # a) { |
+ # In this case the { and the = are on different lines. But the |
+ # override should still apply for all previous stack tokens that are |
+ # part of an assignment of a block. |
+ |
+ has_assignment = any(x for x in self._stack if x.token.IsAssignment()) |
+ if has_assignment: |
+ last_token = token_info.token.previous |
+ for stack_info in reversed(self._stack): |
+ if (last_token and |
+ not self._AllFunctionPropertyAssignTokens(stack_info.token, |
+ last_token)): |
+ break |
+ stack_info.overridden_by = token_info |
+ stack_info.is_permanent_override = True |
+ last_token = stack_info.token |
+ |
+ index = len(self._stack) - 1 |
+ while index >= 0: |
+ stack_info = self._stack[index] |
stack_token = stack_info.token |
if stack_info.line_number == token_info.line_number: |
@@ -492,21 +540,9 @@ class IndentationRules(object): |
close_block = token_info.token.metadata.context.end_token |
stack_info.is_permanent_override = close_block and ( |
close_block.line_number != token_info.token.line_number) |
- elif (token_info.token.type == Type.START_BLOCK and |
- token_info.token.metadata.context.type == Context.BLOCK and |
- (stack_token.IsAssignment() or |
- stack_token.type == Type.IDENTIFIER)): |
- # When starting a function block, the override can transcend lines. |
- # For example |
- # long.long.name = function( |
- # a) { |
- # In this case the { and the = are on different lines. But the |
- # override should still apply. |
- stack_info.overridden_by = token_info |
- stack_info.is_permanent_override = True |
else: |
break |
- index += 1 |
+ index -= 1 |
self._stack.append(token_info) |