This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Add library to semantically strip flags by name.
ClosedPublic

Authored by sammccall on Jun 16 2020, 12:22 PM.

Details

Summary

This is designed for tweaking compile commands by specifying flags to add/remove
in a config file. Something like:

CompileFlags: { Remove: -fcolor-diagnostics }

Having users tweak raw argv (e.g. with a regex) is going to end in tears: bugs
around clang-cl, xclang, aliases, joined-vs-separate args etc are inevitable.

This isn't in tooling because of the performance choices: build a big table
up-front to make subsequent actions fast. Maybe it should be though.

Diff Detail

Event Timeline

sammccall created this revision.Jun 16 2020, 12:22 PM
adamcz added inline comments.Jun 17 2020, 5:48 AM
clang-tools-extra/clangd/CompileCommands.cpp
266

nit: could you replace 10000 with some constant value with descriptive name? It's not immediately clear if this is some significant value (e.g. some flag number or something) or just, as it's the case, just a very large number.

311

typo: treet

411

nit: this function is already quite long and this part seems like a re-usable and self-contained piece. Could we extra this into some GetDriverMode() helper?

441

Correct me if I'm wrong, but this is relying on the fact that Rules are sorted, right? Or, to be more specific, on the fact that -foo comes before -foobar.

Consider two rules in config file, one to remove -include, another to remove -include-pch, in that order. -include will do a prefix match on Arg == -include-pch and attempt to remove exactly one arg (-include is JoinedOrSeparate, which has 1 for PrefixArgs), when in reality that was "--include-pch foo.pch", an exact match on a different option.

So a config like:
Remove: [-include, -include-pch]
and command line:
[-include-pch, foo.pch]
should be [], but ends up being [foo.pch]

It looks like Options.inc is sorted in the correct way (include-pch will always be before -include). I don't know if that's guaranteed, but it looks to be the case. However, since you are adding these options to Rules on each strip() call, you end up depending on the order of strip() calls. That seems like a bug.

hokein added inline comments.Jun 17 2020, 6:56 AM
clang-tools-extra/clangd/CompileCommands.cpp
273

nit: put it into anonymous namespace to avoid potential ODR violation.

304

Is -x* 2 args right? it seems that -xc++ is just 1 arg.

339

nit: add a comment after 1 e.g /*skip the OPT_INVALID*/, explaining why not starting from 0.

435

this loop is long and nested within a tricky while, maybe consider pulling it out a separate function like getMatchedRule.

448

nit: assert(Write > 0)?

clang-tools-extra/clangd/CompileCommands.h
60

Is the glob * supported when the Arg (in strip API) is recognized as an option flag? My reading of the code implies it is not.

Maybe consider moving the above two lines to strip API comment, it is more discoverable.

72

The Args is expected to be a standard compile command? if so, might be name it CompileCommand.

clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
200

add tests for stripping the diagnostic flags, -Wfoo etc.

sammccall updated this revision to Diff 277444.Jul 13 2020, 8:34 AM
sammccall marked 13 inline comments as done.

Address the easy comments, add a test for order-dependency.

sammccall planned changes to this revision.Jul 13 2020, 8:36 AM

Need to work out how to address the order-dependency comment.

clang-tools-extra/clangd/CompileCommands.cpp
441

This is a really good point, I hadn't realized the option table was order-dependent (e.g. I figured -include wasn't a Joined option).

The real option parser processes the options in the order they appear in the file, so that should definitely be correct.
I think processing them longest-to-shortest is probably also correct, since a spelling that's always shadowed by a prefix isn't that useful, I'd hope they don't actually exist.

clang-tools-extra/clangd/CompileCommands.h
60

Yeah you're right, thought I'd phrase more as "-foo*" is never a recognized flag :-)
I've moved the comment as you suggest and regrouped to be clearer.

72

We have this annoying clang-tidy check that wants the impl and decl to have the same arg names, and CompileCommand is too long for the impl.

Updated the doc though.

clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
200

Those aren't actually separate flags: "-W" is a Joined flag and foo is an arg.
Do you want a test specifically for such a string anyway?
Or do you want special behavior for them? (Like interaction between -Wfoo and -Wno-foo)

sammccall updated this revision to Diff 277464.Jul 13 2020, 9:39 AM

Use explicit priority to resolve ambiguities between prefixes.

sammccall marked 2 inline comments as done.Jul 13 2020, 9:41 AM

OK, I think this is good to go now.

clang-tools-extra/clangd/CompileCommands.cpp
441

Opted for explicitly recording the index and traversing all the rules to find the best one (instead of stopping when we find a single match).
This should cost a single factor of 2 and it's really simple.

[clangd] Config: CompileFlags.Remove

While here, add documentation to CompileFlags and CompileFlags.Add.

Sigh, last upload was supposed to be a new patch, not clobber this one.

hokein accepted this revision.Jul 14 2020, 12:06 AM

looks almost good.

clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
200

I was a bit unclear about how the stripper strips the "-W/-D"-like flag, would be nice to have them in tests as I think these are important cases.

Those aren't actually separate flags: "-W" is a Joined flag and foo is an arg.

oh, if I understand correctly:

  • strip("unused", "clang -Wunused foo.cc") => clang foo.cc ?
  • strip("-W", "clang -Wunused -Wextra foo.cc") => clang foo.cc // remove all -W flags ?
  • strip("error=unused", "clang -Wunused -Werror=unused -Werror=date-time foo.cc") => clang -Wunused -Werror=date-time foo.cc?
This revision is now accepted and ready to land.Jul 14 2020, 12:06 AM
sammccall marked an inline comment as done.Jul 14 2020, 3:00 AM
sammccall added inline comments.
clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
200

I was a bit unclear about how the stripper strips the "-W/-D"-like flag, would be nice to have them in tests as I think these are important cases.

Added.

strip("unused", "clang -Wunused foo.cc") => clang foo.cc ?

No, we only strip clang args or flag names, not flag args (confusing terminology).
-W will strip -Wunused (flag name). -Wunused will strip -Wunused (clang arg). -W* will strip -Wunused (clang arg). but "unused" doesn't match - it's not the name of a flag, and it's not the arg either.

strip("-W", "clang -Wunused -Wextra foo.cc") => clang foo.cc // remove all -W flags ?

Yes

strip("error=unused", "clang -Wunused -Werror=unused -Werror=date-time foo.cc") => clang -Wunused -Werror=date-time foo.cc?

No, again we don't strip flag args.
(It's not clear how useful/easy to use this would be, maybe we can re-examine later?)

sammccall updated this revision to Diff 277728.Jul 14 2020, 3:00 AM

Add more tests

hokein accepted this revision.Jul 14 2020, 6:09 AM

still lg.

clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
200

No, we only strip clang args or flag names, not flag args (confusing terminology).
-W will strip -Wunused (flag name). -Wunused will strip -Wunused (clang arg). -W* will strip -Wunused (clang arg). but "unused" doesn't match - it's not the name of a flag, and it's not the arg either.

oh, I was confused by these terms :(

No, again we don't strip flag args.
(It's not clear how useful/easy to use this would be, maybe we can re-examine later?)

we can still strip it by passing "-Werror-unused" arg, right? if so, I think it should be fine.

This revision was automatically updated to reflect the committed changes.
sammccall marked an inline comment as done.
daltenty added inline comments.
clang-tools-extra/clangd/CompileCommands.cpp
15

This breaks the powerpc64le bots. Looks like we aren't linking against Option:

CompileCommands.cpp:(.text._ZZN5clang6clangd11ArgStripper8rulesForEN4llvm9StringRefEENK3$_3clEv+0x514c): undefined reference to `llvm::opt::OptTable::getOption(llvm::opt::OptSpecifier) const'

http://lab.llvm.org:8011/builders/clang-ppc64le-rhel/builds/5697/

sammccall marked an inline comment as done.Jul 14 2020, 8:04 AM
sammccall added inline comments.
clang-tools-extra/clangd/CompileCommands.cpp
15

Thanks! 50a5fa8b9ba4b09433bf46f4228d4e4cae9ac486 will hopefully fix.

(Not sure why this didn't show up on x64 but linking is mostly a mystery to me...)

clang-tools-extra/clangd/unittests/CompileCommandsTests.cpp
200

oh, I was confused by these terms :(

They're confusing. Tried to clarify in the doc.

we can still strip it by passing "-Werror-unused" arg, right? if so, I think it should be fine.

Yeah. (-Werror=unused I guess, but in any case...)

ychen added a subscriber: ychen.Dec 1 2020, 8:40 PM
ychen added inline comments.
clang-tools-extra/clangd/CompileCommands.cpp
356

This emits a huge number of -Wtautological-constant-compare warnings due to ALIAS being OPT_INVALID etc. Enclose this with pragma to disable these warnings?