clang-format behavior for Obj-C methods with block parameters

Hi everyone,

I’m experiencing a problem with clang-format for my code.

I’m using ColumnLimit as 120. When I write some code like this:

[self testMethod:15 withBlock:^{
NSLog(@“asdfasdf”);
NSLog(@“asdfasdf”);
NSLog(@“asdfasdf”);
NSLog(@“asdfasdf”);
}]**;

This code would be converted to this by clang-format:

[self testMethod:15
withBlock:^{
NSLog(@“asdfasdf”);
NSLog(@“asdfasdf”);
NSLog(@“asdfasdf”);
NSLog(@“asdfasdf”);
}];

That seems wrong to me because the method call before block variable actually fits in width of 120. I guess this is because clang-format behaves above code as a single method call and assumes it as one line. But I really want to not split the method like this because it feels weird.

Is there a way to accomplish this with current system?

I put my configuration file as an attachment.

Best

.clang-format (2.02 KB)

Nope, this behavior isn’t currently implemented. I agree that it might make sense, as it is similar to how clang-format treats lambdas at the end of several other parameters.

Thanks for the response Daniel,

Could you guide me on where can I look inside clang-format implementation to see how clang-format currently handles lambdas in other languages, so that I may try to implement the same functionality for Objective-C case?

Besides that, I have one more question, which is somewhat related to topic.

When I try to use clang-format to format the following simple code:

  • (void)asdf {
    [UIView animateasdfasdf:0 animations:^{ }];
    [UIView animations:^{ } done:YES];
    [UIView animations:^{ } completion:^{ }];
    [UIView testasdfasdfsd:YES animations:^{ } completion:^{ }];
    [UIView animations:^{ } tessd:YES completion:^{ }];
    }

Output is the following:

  • (void)asdf {
    [UIView animateasdfasdf:0
    animations:^{
    }];
    [UIView animations:^{
    }
    done:YES];
    [UIView animations:^{
    }
    completion:^{
    }];
    [UIView testasdfasdfsd:YES
    animations:^{
    }
    completion:^{
    }];
    [UIView animations:^{
    }
    tessd:YES
    completion:^{
    }];
    }

I think clang-format somehow decides to not use colon alignment but align using ContinuationIndentWidth where there are more than one block parameters.
Is this an intended behavior? Seems like a bug to me.

Thanks for the response Daniel,

Could you guide me on where can I look inside clang-format implementation to see how clang-format currently handles lambdas in other languages, so that I may try to implement the same functionality for Objective-C case?

Besides that, I have one more question, which is somewhat related to topic.

When I try to use clang-format to format the following simple code:

  • (void)asdf {
    [UIView animateasdfasdf:0 animations:^{ }];
    [UIView animations:^{ } done:YES];
    [UIView animations:^{ } completion:^{ }];
    [UIView testasdfasdfsd:YES animations:^{ } completion:^{ }];
    [UIView animations:^{ } tessd:YES completion:^{ }];
    }

Output is the following:

  • (void)asdf {
    [UIView animateasdfasdf:0
    animations:^{
    }];
    [UIView animations:^{
    }
    done:YES];
    [UIView animations:^{
    }
    completion:^{
    }];
    [UIView testasdfasdfsd:YES
    animations:^{
    }
    completion:^{
    }];
    [UIView animations:^{
    }
    tessd:YES
    completion:^{
    }];
    }

I think clang-format somehow decides to not use colon alignment but align using ContinuationIndentWidth where there are more than one block parameters.
Is this an intended behavior? Seems like a bug to me.

PS : I’m using the default LLVM configuration for the above case.

Thanks for the response Daniel,

Could you guide me on where can I look inside clang-format implementation
to see how clang-format currently handles lambdas in other languages, so
that I may try to implement the same functionality for Objective-C case?

Not really, it is all in ContinuationIndenter.cpp. However, this is among
the most complex code of clang-format and giving you details on how to do
this probably would take me longer than looking at this myself. If you
still want to try and take a look, feel free. I am happy to answer any
specific questions you might have.

Besides that, I have one more question, which is somewhat related to topic.

When I try to use clang-format to format the following simple code:

- (void)asdf {
[UIView animateasdfasdf:0 animations:^{ }];
[UIView animations:^{ } done:YES];
[UIView animations:^{ } completion:^{ }];
[UIView testasdfasdfsd:YES animations:^{ } completion:^{ }];
[UIView animations:^{ } tessd:YES completion:^{ }];
}

Output is the following:

- (void)asdf {
  [UIView animateasdfasdf:0
               animations:^{
               }];
  [UIView animations:^{
  }
                done:YES];
  [UIView animations:^{
  }
      completion:^{
      }];
  [UIView testasdfasdfsd:YES
      animations:^{
      }
      completion:^{
      }];
  [UIView animations:^{
  }
      tessd:YES
      completion:^{
      }];
}

I think clang-format somehow decides to not use colon alignment but align
using `ContinuationIndentWidth` where there are more than one block
parameters.
Is this an intended behavior? Seems like a bug to me.

It is intentional. Column alignment with more than one internal block
doesn't really work. And this is also explicitly written in Google's style
guide: https://google.github.io/styleguide/objcguide.xml#Blocks

Independent of that some of you examples look like there are still other
bugs in there.

PS : I'm using the default LLVM configuration for the above case.

I carefully read the google style guide, and behavior about multiple inline blocks seems reasonable now.However, I still feel it’s not fully consistent because of the third method call example above.
I think that case should have something like the following format in order to be consistent across the code:

[UIView
animations:^{
}
completion:^{
}];

Also there is another case in which formatting messes completely:

[UIView animateWithDuration:123 delay:123 usingSpringWithDamping:123 initialSpringVelocity:123 options:123 animations:^{ } completion:^(BOOL finished){ }];

becomes this:

[UIView animateWithDuration:123
delay:123
usingSpringWithDamping:123
initialSpringVelocity:123
options:123
animations:^{
}
completion:^(BOOL finished){
}];

Is this (cancelling colon alignment also for non-block parameters ) also intentional?
If so, I understand that clang-format will apply standard ContinuationIndentWidth value whenever a method call includes more than one inline blocks.

I question this scenario too much because the above code is a frequent code block to animate views on screen, and having a consistent behavior is important in order to use clang-format’s automatic formatting without any hesitancy

Thanks for the response Daniel,

Could you guide me on where can I look inside clang-format implementation
to see how clang-format currently handles lambdas in other languages, so
that I may try to implement the same functionality for Objective-C case?

Not really, it is all in ContinuationIndenter.cpp. However, this is among
the most complex code of clang-format and giving you details on how to do
this probably would take me longer than looking at this myself. If you
still want to try and take a look, feel free. I am happy to answer any
specific questions you might have.

Besides that, I have one more question, which is somewhat related to
topic.

When I try to use clang-format to format the following simple code:

- (void)asdf {
[UIView animateasdfasdf:0 animations:^{ }];
[UIView animations:^{ } done:YES];
[UIView animations:^{ } completion:^{ }];
[UIView testasdfasdfsd:YES animations:^{ } completion:^{ }];
[UIView animations:^{ } tessd:YES completion:^{ }];
}

Output is the following:

- (void)asdf {
  [UIView animateasdfasdf:0
               animations:^{
               }];
  [UIView animations:^{
  }
                done:YES];
  [UIView animations:^{
  }
      completion:^{
      }];
  [UIView testasdfasdfsd:YES
      animations:^{
      }
      completion:^{
      }];
  [UIView animations:^{
  }
      tessd:YES
      completion:^{
      }];
}

I think clang-format somehow decides to not use colon alignment but align
using `ContinuationIndentWidth` where there are more than one block
parameters.
Is this an intended behavior? Seems like a bug to me.

It is intentional. Column alignment with more than one internal block
doesn't really work. And this is also explicitly written in Google's style
guide: https://google.github.io/styleguide/objcguide.xml#Blocks

Independent of that some of you examples look like there are still other
bugs in there.

I carefully read the google style guide, and behavior about multiple
inline blocks seems reasonable now.
However, I still feel it's not fully consistent because of the third
method call example above.
I think that case should have something like the following format in order
to be consistent across the code:

[UIView
    animations:^{
    }
    completion:^{
    }];

As I mentioned in my previous email, there are cases in your example that
look buggy to me. I was just stating that in general, this is intended.

Also there is another case in which formatting messes completely:

  [UIView animateWithDuration:123 delay:123 usingSpringWithDamping:123
initialSpringVelocity:123 options:123 animations:^{ } completion:^(BOOL
finished){ }];

becomes this:

  [UIView animateWithDuration:123
      delay:123
      usingSpringWithDamping:123
      initialSpringVelocity:123
      options:123
      animations:^{
      }
      completion:^(BOOL finished){
      }];

Is this (cancelling colon alignment also for non-block parameters ) also
intentional?

It is intended and I think it makes sense. However, I have never worked on
ObjC code, so my understanding of the pros and cons is *very* limited.

If so, I understand that clang-format will apply standard
`ContinuationIndentWidth` value whenever a method call includes more than
one inline blocks.

I question this scenario too much because the above code is a frequent
code block to animate views on screen, and having a consistent behavior is
important in order to use clang-format’s automatic formatting without any
hesitancy

Sure, I understand. But as I mentioned above, I might actually not be the
best person to ask. As the main author of clang-format, I try to support
ObjC on a best-effort basis, without understanding much of it. There is
also limited time I can spend on this at least in the foreseeable future.

Cheers
Daniel

Hi Daniel,

Are you OK with an option like “ObjCColonAlignMultipleBlocks” which aligns multiple block arguments from colon. I think this is needed because aligning multiple block arguments from colon character is so common in Objective-C community. It’s also the default indentation behavior of Xcode.

We can still set this to false by default, but could provide an option to disable that behavior?

I’ve done an implementation internally, if you’re OK and suggest a proper key, I can send a patch for it.

I don’t know anything about that, don’t use ObjC myself. The main problem will be finding someone who can maintain this in the long(er) run. Adding Nico for additional thoughts.