firolino added inline comments.

================
Comment at: clang-tidy/readability/OneNamePerDeclarationCheck.cpp:34
+  // a tag declaration (e.g. struct, class etc.):
+  // class A { } Object1, Object2;  <-- won't be matched
+  Finder->addMatcher(
----------------
aaron.ballman wrote:
> firolino wrote:
> > aaron.ballman wrote:
> > > firolino wrote:
> > > > aaron.ballman wrote:
> > > > > firolino wrote:
> > > > > > aaron.ballman wrote:
> > > > > > > firolino wrote:
> > > > > > > > firolino wrote:
> > > > > > > > > firolino wrote:
> > > > > > > > > > firolino wrote:
> > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > firolino wrote:
> > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > Why do we not want to match this?
> > > > > > > > > > > > > If we decide, whether we transform 
> > > > > > > > > > > > > ```
> > > > > > > > > > > > > class A { 
> > > > > > > > > > > > > } Object1, Object2;
> > > > > > > > > > > > > ``` 
> > > > > > > > > > > > > to
> > > > > > > > > > > > > ```
> > > > > > > > > > > > > class A { 
> > > > > > > > > > > > > } Object1, 
> > > > > > > > > > > > > Object2;
> > > > > > > > > > > > > ``` 
> > > > > > > > > > > > > or
> > > > > > > > > > > > > ```
> > > > > > > > > > > > > class A { 
> > > > > > > > > > > > > } 
> > > > > > > > > > > > > Object1, 
> > > > > > > > > > > > > Object2;
> > > > > > > > > > > > > ``` 
> > > > > > > > > > > > > I might consider adding support for it. Moreover, 
> > > > > > > > > > > > > this kind of definition is usually seen globally and 
> > > > > > > > > > > > > I don't know how to handle globals yet. See 
> > > > > > > > > > > > > http://lists.llvm.org/pipermail/cfe-dev/2015-November/046262.html
> > > > > > > > > > > > I think this should be handled. It can be handled in 
> > > > > > > > > > > > either of the forms you show, or by saying:
> > > > > > > > > > > > ```
> > > > > > > > > > > > A Object1;
> > > > > > > > > > > > A Object2;
> > > > > > > > > > > > ```
> > > > > > > > > > > > If all of these turn out to be a problem, we can still 
> > > > > > > > > > > > diagnose without providing a fixit.
> > > > > > > > > > > > 
> > > > > > > > > > > > As for globals in general, they can be handled in a 
> > > > > > > > > > > > separate patch once we figure out the declaration 
> > > > > > > > > > > > grouping.
> > > > > > > > > > > OK. I will try to split the object definition from the 
> > > > > > > > > > > class definition, as you have suggested. Thus, I can kick 
> > > > > > > > > > > out the tagDecl-matcher as well. If there is no easy way 
> > > > > > > > > > > to do this, it will be reported anyway but without a 
> > > > > > > > > > > fixit.
> > > > > > > > > > > 
> > > > > > > > > > > Note for me: Update documentation!
> > > > > > > > > > What about
> > > > > > > > > > ```
> > > > > > > > > > struct S {
> > > > > > > > > > } S1;
> > > > > > > > > > ```
> > > > > > > > > > I would like to report this too, since two names are being 
> > > > > > > > > > declared here. `S` and `S1`. What do you think?
> > > > > > > > > ```
> > > > > > > > > struct {
> > > > > > > > > } nn1, nn2;
> > > > > > > > > ```
> > > > > > > > > Shall we ignore anonymous definitions?
> > > > > > > > To be more precise: Warn and provide a fixit for `struct S {} 
> > > > > > > > S1`. Only warn for `struct {} nn1, nn2`.
> > > > > > > > What about
> > > > > > > > 
> > > > > > > > ```
> > > > > > > > struct S {
> > > > > > > > } S1;
> > > > > > > > ```
> > > > > > > > I would like to report this too, since two names are being 
> > > > > > > > declared here. S and S1. What do you think?
> > > > > > > 
> > > > > > > I don't think that this should be diagnosed. For one, this is a 
> > > > > > > relatively common pattern (arguably more common than `struct S { 
> > > > > > > } S1, S2;`), but also, it names two very distinct entities (a 
> > > > > > > type and a variable).
> > > > > > > 
> > > > > > > > ```
> > > > > > > > struct {
> > > > > > > > } nn1, nn2;
> > > > > > > >```
> > > > > > > > Shall we ignore anonymous definitions?
> > > > > > > 
> > > > > > > Yes, we basically have to.
> > > > > > > 
> > > > > > Transforming
> > > > > > ```
> > > > > > typedef struct X { int t; } X, Y;
> > > > > > ```
> > > > > > to
> > > > > > ```
> > > > > > typedef struct X { int t; };
> > > > > > typedef X X;
> > > > > > typedef X Y;
> > > > > > ```
> > > > > > will be valid, but looks odd.
> > > > > I am on the fence about this transformation -- it does not declare 
> > > > > new objects, but instead declares new types. A very common pattern in 
> > > > > some libraries (such as the Win32 SDK) is to declare:
> > > > > ```
> > > > > typedef struct Blah {
> > > > > 
> > > > > } Blah, *PBlah, **PPBlah;
> > > > > ```
> > > > > Because of that pattern, diagnosing the above typedef is likely to be 
> > > > > very chatty in some projects, and I don't know that the fixit 
> > > > > provides much real benefit for types.
> > > > > 
> > > > > At least for the CERT DCL04-C version of this rule, that code should 
> > > > > not be flagged. Do you think any of the variations of this check 
> > > > > should flag it?
> > > > Maybe we should reconsider where to split and where not. The original 
> > > > idea was to minimize confusion on code like
> > > > ```
> > > > int* a,b;
> > > > ```
> > > > whereas 
> > > > ```
> > > > struct S {} *s1, s2;
> > > > ```
> > > > seems not so confusing as above. However, 
> > > > ```
> > > > struct S {}* s1, s2;
> > > > ```
> > > > looks dangerous again.
> > > > 
> > > > Even following code looks unfamiliar to me.
> > > > ```
> > > > typedef struct Blah {} Blah, *PBlah;
> > > > ```
> > > > 
> > > > It really depends on the beholder. So, how about letting this check 
> > > > split **everything** and provide options for maximum flexibility? So 
> > > > specific rulesets or the user may configure it as they wish. We could 
> > > > add for example split-after-tag-def, split-tag-typedef in addition to 
> > > > cppcore and cert and use a default setting (split-after-tag-def=true, 
> > > > split-tag-typedef=false).
> > > I've typically found that users go with whatever the default options are, 
> > > rather than specify a slew of options, and if the default options produce 
> > > an onerous check, they simply disable the entire check. I'd rather not 
> > > push the design off to the users unless there's really no better 
> > > alternative.
> > > 
> > > I think that the only "dangerous" operations this sort of check is meant 
> > > to catch is when the declaration group uses different specifiers for the 
> > > declarator or when there's an initializer on one declarator but none of 
> > > the rest. I think the other operations are more likely to be a 
> > > consistency thing than a bug-prone thing. e.g.,
> > > ```
> > > // Differing specifiers
> > > int i, j, k; // Not at all likely to be mistaken code.
> > > int i, *j, &k; // Not really likely to be mistaken code.
> > > int *i, j; // More likely to be mistaken code.
> > > int i, *j; // Not really likely to be mistaken code.
> > > typedef int *one, two, three; // More likely to be mistaken code.
> > > typedef int one, *two, **three; // Not really likely to be mistaken code.
> > > 
> > > // Initialization
> > > int i = 10, j = 10; // Not at all likely to be mistaken code.
> > > int i = 10, j; // Not really likely to be mistaken code.
> > > int i, j = 10; // More likely to be mistaken code.
> > > ```
> > > I think declarations that declare both types and variables should ignore 
> > > the type name and focus only on the variable name following the same 
> > > heuristics. e.g.,
> > > ```
> > > struct S {} s; // Not at all likely to be mistaken code.
> > > struct S {} s, *t; // Not really likely to be mistaken code.
> > > struct S {} *s, t; // More likely to be mistaken code.
> > > ```
> > > I could imagine an option like `FlagPossiblyDangerous` or something else; 
> > > if the flag is set, the check diagnoses based on some heuristic of likely 
> > > dangerous operations and if the flag is not set, the check flags all 
> > > declarators in the same declaration.
> > > 
> > > What do you think?
> > We are judging from our perspective what is "likely dangerous" and this 
> > might not agree with the users view. This is why I don't wanna force any 
> > limitations based on our decisions. This check might not be used only to 
> > reduce "readability error" but even for a simple style guide enforcement 
> > that wants one variable declaration per line.
> > 
> > I know that `int i, j, k;` is not bad at all or likely to be mistaken, but 
> > style guides from [[ https://www.openssl.org/policies/codingstyle.txt | 
> > openssl]] or the [[ 
> > https://www.kernel.org/doc/Documentation/process/coding-style.rst | linux 
> > kernel ]] are enforcing one declaration per line.
> > 
> > > I've typically found that users go with whatever the default options are
> > So, why not simple use options and set the default whatever we think is 
> > right. We are not loosing anything with this way, just getting more 
> > flexible. Anyone else can reset the options to their needs.
> > 
> > I would think of following options:
> > `Style = Default, CppCore, Cert`
> > `SplitTagDef = True, False`
> > `SplitTagTypeDef = True, False`
> > 
> > and with default:
> > ```
> > Style = Default     # splits anything, regardless of tokens and initializers
> > SplitTagDef = True
> > SplitTagTypeDef = False
> > ```
> > 
> > The check will be registered under cert with `Style = Cert` and `CppCore` 
> > for cppcore respectively. 
> > 
> > And since it is topic related, there are still two things on my todo list:
> >   - attributes
> >   - members
> > 
> > ```
> > struct alignas(8) S {} s1, s2;
> > alignas(8) char a, b;
> > [[maybe_unused]] bool x, y;
> > 
> > struct S {
> >   int a, b;
> > };
> > ```
> > Should we include this as well, or leave it for future work?
> > 
> > So, why not simple use options and set the default whatever we think is 
> > right. We are not loosing anything with this way, just getting more 
> > flexible. Anyone else can reset the options to their needs.
> 
> I think we are describing the same solution, but perhaps from different 
> angles. I am proposing that we have this checker flag everything, but that we 
> have a sensible set of default options that reduce the number of diagnostics 
> issued for existing code bases. I fear that if the default behavior of this 
> check is to point out *every* declaration group with more than one name being 
> declared, the output will be way too chatty and so the entire check is 
> disabled. I think that if we had a default behavior that only pointed out the 
> suspicious declarations, that would reduce the "noise" by default. One way to 
> test this would be to run the check over some large code bases of various 
> style guides to see how many results there are. I would recommend running it 
> over the LLVM and Clang code bases (which do not have a restriction on 
> declarations) and OpenSSL (which does have this restriction) and report back 
> the diagnostics you get from each (as well as totals). Feel free to pick 
> other/additional code bases to test again.
> 
> > Should we include this as well, or leave it for future work?
> 
> It's up to you, but I think it's reasonable to leave for future work. 
> Attributes are likely to be somewhat harder than members in many regards due 
> to where attributes can be written. I suspect that members can be handled 
> like variable declarations in general.
OK, I get what you mean. Btw, thanks for taking your time! This review gets 
longer and longer :)


https://reviews.llvm.org/D27621



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to