This is an archive of the discontinued LLVM Phabricator instance.

[clang-format] Support clang-format on/off line comments as prefixes
ClosedPublic

Authored by owenpan on Jan 28 2023, 3:00 AM.

Diff Detail

Event Timeline

owenpan created this revision.Jan 28 2023, 3:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 28 2023, 3:00 AM
owenpan requested review of this revision.Jan 28 2023, 3:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 28 2023, 3:00 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
rymiel added inline comments.Jan 28 2023, 3:06 AM
clang/lib/Format/Format.cpp
3901

Should the space be required? What about // clang-format off: reasoning or similar?

Also, should this be documented?

clang/lib/Format/Format.cpp
3901

Should the space be required? What about // clang-format off: reasoning or similar?

Also, should this be documented?

+1

alexolog added inline comments.
clang/lib/Format/Format.cpp
3893

Here's my attempt at something flexible:
Disclaimer: this is my first time looking at the LLVM codebase, so don't expect production quality.

////////////////////////////////////////////////////////////////////////////////////////////////////

// Implementation detail, hide in a namespace and/or take out of the header
bool isClangFormatMarked(StringRef Comment, StringRef Mark) {
  // Quick heuristics: minimum length and starts with a slash (comment)
  // Shortest tag: "//clang-format on", 17 characters
  static constexpr StringLiteral clangFormatStr("clang-format ");
  if (Comment.size() < clangFormatStr.size() + 4 || Comment[0] != '/')
    return false;

  // check if it's a comment starting with "//" or "/*"
  bool CloseNeeded = false;
  if (Comment[1] == '*')
    CloseNeeded = true;
  else if (Comment[1] != '/')
    return false;

  // Remove the comment start and all following whitespace
  Comment = Comment.substr(2).ltrim();

  // Check for the actual command, a piece at a time
  if (!Comment.consume_front(clangFormatStr) || !Comment.consume_front(Mark))
    return false;

  // Are we there yet?
  if (!CloseNeeded && Comment.empty() ||
      CloseNeeded && Comment.starts_with("*/"))
    return true;

  // For a trailer, restrict the next character
  // (currently spaces and tabs, but can include a colon, etc.)
  static constexpr StringLiteral Separator(" \t");
  if (!Separator.contains(Comment[0]))
    return false;
  
  // Verify comment is properly terminated
  if (!CloseNeeded || Comment.contains("*/"))
    return true;

  return false; // Everything else
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool isClangFormatOn(StringRef Comment) {
  return isClangFormatMarked(Comment, "on");
}

bool isClangFormatOff(StringRef Comment) {
  return isClangFormatMarked(Comment, "off");
}

////////////////////////////////////////////////////////////////////////////////////////////////////

  EXPECT_TRUE(isClangFormatOn("//clang-format on"));
  EXPECT_TRUE(isClangFormatOn("// clang-format on"));
  EXPECT_TRUE(isClangFormatOn("//clang-format on "));
  EXPECT_TRUE(isClangFormatOn("//clang-format on and off"));
  EXPECT_TRUE(isClangFormatOn("/*clang-format on*/"));
  EXPECT_TRUE(isClangFormatOn("/* clang-format on*/"));
  EXPECT_TRUE(isClangFormatOn("/*clang-format on */"));
  EXPECT_TRUE(isClangFormatOn("/*clang-format on*/int i{0};"));

  EXPECT_FALSE(isClangFormatOn("//clang-format  on"));
  EXPECT_FALSE(isClangFormatOn("//clang-format o"));
  EXPECT_FALSE(isClangFormatOn("//     clang-format o"));
  EXPECT_FALSE(isClangFormatOn("//clang-format ontario"));
  EXPECT_FALSE(isClangFormatOn("//clang-format off"));
  EXPECT_FALSE(isClangFormatOn("/*clang-format onwards*/"));

////////////////////////////////////////////////////////////////////////////////////////////////////
alexolog added inline comments.Jan 28 2023, 2:17 PM
clang/lib/Format/Format.cpp
3893

Sorry about the "done". My misunderstanding

owenpan added inline comments.Jan 28 2023, 9:43 PM
clang/lib/Format/Format.cpp
3893

Here's my attempt at something flexible:
Disclaimer: this is my first time looking at the LLVM codebase, so don't expect production quality.

Thanks! If we didn't have to worry about regressions, we might want to do something like what you suggested above.

3901

Should the space be required? What about // clang-format off: reasoning or similar?

On second thought, we should make it more restrictive to avoid regressions. How about requiring a colon, i.e. // clang-format off: (but not // clang-format off :)?

Also, should this be documented?

Yep.

owenpan updated this revision to Diff 493069.Jan 28 2023, 11:07 PM

Only allows : as the first character after // clang-format on or // clang-format off.

owenpan marked 2 inline comments as done.Jan 28 2023, 11:08 PM
clang/lib/Format/Format.cpp
3901

Should the space be required? What about // clang-format off: reasoning or similar?

On second thought, we should make it more restrictive to avoid regressions. How about requiring a colon, i.e. // clang-format off: (but not // clang-format off :)?

That's fine by me. But why not also /**/?

owenpan updated this revision to Diff 493180.Jan 29 2023, 7:25 PM

Improves isClangFormatOnOff() a little bit.

owenpan added inline comments.Jan 29 2023, 7:30 PM
clang/lib/Format/Format.cpp
3901

But why not also /**/?

If it weren't for the fact that the code which checks for clang-format on/off exists in several places, I wouldn't want this feature added. IMO there's no need to allow /* clang-format off: */ if we got // clang-format: and being more restrictive results in a lower risk of regression.

alexolog added inline comments.Jan 29 2023, 9:11 PM
clang/lib/Format/Format.cpp
3893

Isn't it what extensive test coverage is for?

This revision is now accepted and ready to land.Jan 30 2023, 2:03 AM
owenpan added inline comments.Jan 30 2023, 3:38 AM
clang/lib/Format/Format.cpp
3893

I meant the regression of behavior.

This revision was landed with ongoing or failed builds.Feb 1 2023, 1:07 PM
This revision was automatically updated to reflect the committed changes.