================
Comment at: clang-tidy/readability/RedundantVoidArg.cpp:41
@@ +40,3 @@
+bool protoTypeHasNoParms(QualType QT) {
+ if (const auto PT = QT->getAs<PointerType>()) {
+ QT = PT->getPointeeType();
----------------
alexfh wrote:
> Please use either "auto" or "const auto *" consistently. This function has
> usages of both.
Fixed
================
Comment at: clang-tidy/readability/RedundantVoidArg.cpp:148
@@ +147,3 @@
+ std::string DeclText = getText(Result, Start, BeforeBody);
+ removeVoidArgumentTokens(Result, Start, DeclText, "function definition");
+ } else {
----------------
xazax.hun wrote:
> You can also pass std::string to an llvm::StringRef. In the llvm codebase it
> is a rule of thumb to use StringRef instead of const std::string&.
Fixed.
================
Comment at: clang-tidy/readability/RedundantVoidArg.cpp:158
@@ +157,3 @@
+ const std::string &DeclText, StringRef GrammarLocation) {
+ clang::Lexer PrototypeLexer(StartLoc, Result.Context->getLangOpts(),
+ DeclText.data(), DeclText.data(),
----------------
xazax.hun wrote:
> It is possible to create a lexer without creating an std::string. You can
> check an example in: http://reviews.llvm.org/D7375 (look for getBuffer and
> getCharacterData). Of course, this way you have to make sure to end lexing
> after the interested position is left, but you avoid the heap allocation.
This suggestion has been made several times during this review and every time I
try it I get this error at runtime:
```
void clang::Lexer::InitLexer(const char *, const char *, const char *):
Assertion `BufEnd[0] == 0 && "We assume that the input buffer has a null
character at the end" " to simplify lexing!"' failed.
```
If you can show me how to lex a SourceRange without getting that error, I'm
happy to change it. I tried the method shown in the linked diff and I get the
same error.
However, one good thing came from the experiment. This checker only creates
fixits that remove text, so I don't need to compute replacement text and this
simplified the replacement code a little bit more.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:42
@@ +41,3 @@
+ if (const auto PT = QT->getAs<PointerType>()) {
+ if (const auto FP = PT->getPointeeType()->getAs<FunctionProtoType>()) {
+ return FP->getNumParams() == 0;
----------------
sbenza wrote:
> Remove the duplicate logic.
> Could be something like:
>
> ```
> if (const auto PT = QT->getAs<PointerType>()) {
> QT = PT->getPointeeType();
> }
> if (const auto *MPT = QT->getAs<MemberPointerType>()) {
> QT = MPT->getPointeeType();
> }
> if (const auto FP = QT->getAs<FunctionProtoType>()) {
> return FP->getNumParams() == 0;
> }
> ```
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:73
@@ +72,3 @@
+ const LangOptions &LangOpts = Compiler.getLangOpts();
+ CPlusPlusFile_ = LangOpts.CPlusPlus || LangOpts.CPlusPlus11 ||
+ LangOpts.CPlusPlus14 || LangOpts.CPlusPlus1z;
----------------
xazax.hun wrote:
> As far as I can remember when the code compiled in e.g.: CPlusPlus14 mode,
> the CPlusPlus11 and CPlusPlus flags are also turned on. It might be enough
> to check CPlusPlus.
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:176
@@ +175,3 @@
+ Token ProtoToken;
+ const auto Diagnostic = "redundant void argument list in " + GrammarLocation;
+ while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) {
----------------
alexfh wrote:
> s/const auto/std::string/
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:186
@@ +185,3 @@
+ if (ProtoToken.is(tok::TokenKind::kw_void) ||
+ (ProtoToken.is(tok::TokenKind::raw_identifier) &&
+ ProtoToken.getRawIdentifier() == "void")) {
----------------
alexfh wrote:
> You don't need to check for both kw_void and raw_identifier + "void". You
> won't see the former unless you resolve the identifier and set the token kind
> yourself.
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:219
@@ +218,3 @@
+ if (protoTypeHasNoParms(Typedef->getUnderlyingType())) {
+ auto Text = getText(Result, *Typedef);
+ removeVoidArgumentTokens(Result, Typedef->getLocStart(), Text, "typedef");
----------------
alexfh wrote:
> Please use `StringRef` instead of `auto` here (see the other code review
> thread for an explanation).
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:227
@@ +226,3 @@
+ if (protoTypeHasNoParms(Member->getType())) {
+ const auto Text = getText(Result, *Member);
+ removeVoidArgumentTokens(Result, Member->getLocStart(), Text,
----------------
alexfh wrote:
> StringRef
Fixed
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:241
@@ +240,3 @@
+ .getLocWithOffset(-1);
+ const auto Text = getText(Result, Begin, InitStart);
+ removeVoidArgumentTokens(Result, Begin, Text,
----------------
alexfh wrote:
> s/const auto/StringRef/
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:255
@@ +254,3 @@
+ if (protoTypeHasNoParms(NamedCast->getTypeAsWritten())) {
+ const auto AngleBrackets = NamedCast->getAngleBrackets();
+ const auto Begin = AngleBrackets.getBegin().getLocWithOffset(1);
----------------
alexfh wrote:
> s/const auto/SourceLocation/
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:267
@@ +266,3 @@
+ if (protoTypeHasNoParms(CStyleCast->getTypeAsWritten())) {
+ const auto Begin = CStyleCast->getLParenLoc().getLocWithOffset(1);
+ const auto End = CStyleCast->getRParenLoc().getLocWithOffset(-1);
----------------
alexfh wrote:
> auto
Fixed
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:65
@@ +64,3 @@
+ Finder->addMatcher(typedefDecl(isExpansionInMainFile()).bind(TypedefId),
this);
+ auto FunctionOrMemberPointer = anyOf(hasType(pointerType()),
hasType(memberPointerType()));
+ Finder->addMatcher(fieldDecl(FunctionOrMemberPointer,
isExpansionInMainFile()).bind(FieldId), this);
----------------
sbenza wrote:
> LegalizeAdulthood wrote:
> > sbenza wrote:
> > > The callbacks are not cheap. They generate string copies and then rerun
> > > the tokenizer on them.
> > > These matchers should be more restricted to what we are looking for to
> > > avoid running the callbacks on uninteresting nodes.
> > So... I need to write an expression that matches not just a pointer to
> > function but a pointer to function with zero arguments? I'll play with
> > clang-query and see what I can figure out.
> >
> > I managed to get some narrowing for everything but typedefDecl; I couldn't
> > find any narrowing matchers for it.
> It doesn't have to be a perfect matcher, but it should try to reject the most
> common false positives early.
> Just by saying that it is a functionType() you get most of the varDecls out
> of the way without going into the callback.
> This should be good for now.
I did find ways to reject more cases before beginning a lexical scan of text,
so I'm opting out earlier than I was initially.
I couldn't find the right matcher incantation with `clang-query` to narrow it
further in the matcher instead of in the callback.
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:78
@@ +77,3 @@
+ BoundNodes const &Nodes = Result.Nodes;
+ if (FunctionDecl const *const Function =
Nodes.getNodeAs<FunctionDecl>(FunctionId)) {
+ processFunctionDecl(Result, Function);
----------------
sbenza wrote:
> why not auto in this one? You used it on all other cases below.
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:169
@@ +168,3 @@
+void RemoveVoidArg::processTypedefDecl(const MatchFinder::MatchResult &Result,
TypedefDecl const *const Typedef) {
+ std::string const Text = getText(Result, *Typedef);
+ removeVoidArgumentTokens(Result, Typedef->getLocStart(), Text, "Redundant
void argument list in typedef.");
----------------
xazax.hun wrote:
> I think in the LLVM codebase consts tend to be written before the type and
> not after.
Fixed
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:170
@@ +169,3 @@
+ std::string const Text = getText(Result, *Typedef);
+ removeVoidArgumentTokens(Result, Typedef->getLocStart(), Text, "Redundant
void argument list in typedef.");
+}
----------------
alexfh wrote:
> 1. The "Redundant void argument list in" part is repeated everywhere. Maybe
> just pass the description of the location (here - "typedef") as an argument
> to `removeVoidArgumentTokens`?
>
> 2. Clang-tidy messages should use the same style as Clang diagnostics: start
> with a lower-case letter, and no trailing period.
Fixed
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:174
@@ +173,3 @@
+void RemoveVoidArg::processFieldDecl(const MatchFinder::MatchResult &Result,
FieldDecl const *const Member) {
+ std::string const Text = getText(Result, *Member);
+ removeVoidArgumentTokens(Result, Member->getLocStart(), Text, "Redundant
void argument list in field declaration.");
----------------
LegalizeAdulthood wrote:
> LegalizeAdulthood wrote:
> > sbenza wrote:
> > > LegalizeAdulthood wrote:
> > > > sbenza wrote:
> > > > > LegalizeAdulthood wrote:
> > > > > > sbenza wrote:
> > > > > > > LegalizeAdulthood wrote:
> > > > > > > > sbenza wrote:
> > > > > > > > > Any reason all of these convert the StringRef into a
> > > > > > > > > std::string?
> > > > > > > > > Couldn't they work with the StringRef directly?
> > > > > > > > I tried switching it to a StringRef, but when I tried to
> > > > > > > > combine it with other text to build a replacement for diag(),
> > > > > > > > it got turned into Twine and then failed to match any signature
> > > > > > > > for diag(). I'm open to suggestions for what you'd like to see
> > > > > > > > instead.
> > > > > > > Twine::str() constructs the string.
> > > > > > > I don't mind constructing a string when a match happens. Those
> > > > > > > are rare.
> > > > > > > But we should avoid allocating memory when no match happens.
> > > > > > > Right now temporary memory allocations are a considerable part of
> > > > > > > clang-tidy's runtime. We should try to minimize that.
> > > > > > I think we are at that stage now; I do all early-out testing before
> > > > > > constructing the replacement string.
> > > > > You are still generating a copy of the code before re-parsing it.
> > > > > Those will happen for anything that passes the matcher, even if they
> > > > > have no 'void' argument.
> > > > > removeVoidArgumentTokens should take the code as a StringRef directly
> > > > > from getText(), without converting to std::string first.
> > > > > GrammarLocation should also be a StringRef.
> > > > > Basically, avoid std::string until you are about to call diag().
> > > > I'll look into having getText return the StringRef and using that. I
> > > > don't understand the fuss over GrammarLocation, however. Before I had
> > > > it as a constant string that was just passed through and then another
> > > > review wanted the duplication in the message eliminated, so I pulled
> > > > that out. Now you're saying that the string joining induced by the
> > > > elimination of duplication is bad. It doesn't seem possible to satisfy
> > > > both comments.
> > > The problem with GrammarLocation is that it is declared as a 'const
> > > std::string &' and you are always passing literals.
> > > This is what StringRef is for. It will avoid the unnecessary temporary
> > > string.
> > > The signature would read like:
> > >
> > > void RemoveVoidArg::removeVoidArgumentTokens(
> > > const MatchFinder::MatchResult &Result, SourceLocation StartLoc,
> > > StringRef DeclText, StringRef GrammarLocation);
> > >
> > > Then you can construct the Lexer with an std::string, like:
> > >
> > > clang::Lexer PrototypeLexer(StartLoc, Result.Context->getLangOpts(),
> > > DeclText.data(), DeclText.data(),
> > > DeclText.data() + DeclText.length());
> > >
> > >
> > Thanks for the explanation. I'll try to take a look at this tonight.
> > There is similar code in some of the other reviews I have posted, so I'll
> > fold that into those reviews as well.
> I tried this and it almost works :-). StringRef doesn't put a NUL at the end
> and the lexer needs that:
>
> ```
> clang-tidy: /llvm/tools/clang/lib/Lex/Lexer.cpp:63: void
> clang::Lexer::InitLexer(const char *, const char *, const char *): Assertion
> `BufEnd[0] == 0 && "We assume that the input buffer has a null character at
> the end" " to simplify lexing!"' failed.
> ```
>
> So it looks like I still need to create a std::string right before lexing.
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:105
@@ +104,3 @@
+ const BoundNodes &Nodes = Result.Nodes;
+ if (const auto Function = Nodes.getNodeAs<FunctionDecl>(FunctionId)) {
+ processFunctionDecl(Result, Function);
----------------
alexfh wrote:
> I think, the "const" here makes the code less readable and doesn't add any
> value as the variable is only visible to a one-line statement. Same for the
> other conditions.
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.cpp:207
@@ +206,3 @@
+void RemoveVoidArg::processFieldDecl(const MatchFinder::MatchResult &Result,
+ const FieldDecl *const Member) {
+ const std::string Text = getText(Result, *Member);
----------------
alexfh wrote:
> Please remove top-level const in the method definitions as well.
Fixed
================
Comment at: clang-tidy/readability/RemoveVoidArg.h:26
@@ +25,3 @@
+/// int foo(void); ==> int foo();
+class RemoveVoidArg : public ClangTidyCheck
+{
----------------
LegalizeAdulthood wrote:
> alexfh wrote:
> > Formatting is off in many places. Could you clang-format the code so I
> > don't need to point to every nit?
> I just assumed a final pass through clang-format before being committed; I
> haven't gone through CLion trying to make it follow clang's/llvm's indent
> rules.
Fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.h:38
@@ +37,3 @@
+private:
+ void processFunctionDecl(const ast_matchers::MatchFinder::MatchResult
&Result, FunctionDecl const *const Function);
+
----------------
LegalizeAdulthood wrote:
> sbenza wrote:
> > LegalizeAdulthood wrote:
> > > sbenza wrote:
> > > > alexfh wrote:
> > > > > Here and below: I'm against top-level `const` in function parameter
> > > > > types. It's just an implementation detail whether the method can
> > > > > modify its parameter. It doesn't make sense to pollute the interface
> > > > > with this.
> > > > >
> > > > > Also, it's more common in Clang/LLVM code to put the const related to
> > > > > the pointed/referenced object in front:
> > > > >
> > > > > void processFunctionDecl(const
> > > > > ast_matchers::MatchFinder::MatchResult &Result, const FunctionDecl
> > > > > *Function);
> > > > Any reason why these are members?
> > > > Making them free functions in the .cpp file would avoid filling the
> > > > header with these implementation details.
> > > > It would also remove the need to include Lexer.h here.
> > > They're members because ultimately on detection they ultimately call diag
> > > which is a member function. Otherwise, I would have made them free
> > > functions.
> > They could still be free functions, that return some data instead of taking
> > action directly.
> > But I understand now.
> They'd essentially have to return all the arguments in this statement:
>
> ```
> diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidRange);
> ```
> ...which feels tortured just to avoid creating member functions on the
> implementation.
const issues fixed.
================
Comment at: clang-tidy/readability/RemoveVoidArg.h:38
@@ +37,3 @@
+private:
+ bool CPlusPlusFile_;
+
----------------
alexfh wrote:
> LegalizeAdulthood wrote:
> > alexfh wrote:
> > > 1. You don't need to store this flag as it's easy and cheap to check it
> > > on each call to `check()`: it's available as
> > > `Result.Context->getLangOpts().CPlusPlus`.
> > > 2. This name violates LLVM Naming conventions:
> > > http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly
> > Thanks for showing me where I could get that option. I drilled around in
> > the code for a while and couldn't find it except hanging off the Compiler.
> > What would be really nice is if I could get ahold of that flag when I'm
> > asked to add matchers as I could simply not add any matchers in that case,
> > but `registerPPCallbacks` is called after `registerMatchers`. Can I
> > navigate to it from `ClangTidyContext`?
> Language options only become available when a compiler instance is being
> initialized. The matchers are registered way before that and then multiple
> different compilations may be run potentially with different options (if
> multiple translation units have been passed to clang-tidy).
>
> So there's no way to learn what language will be analyzed when we register
> matchers.
Fixed.
================
Comment at: test/clang-tidy/readability-remove-void-arg.cpp:28
@@ +27,3 @@
+int (*returns_fn_void_int(void))(void);
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: Redundant void argument list in
function declaration. [readability-remove-void-arg]
+// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: Redundant void argument list in
function declaration. [readability-remove-void-arg]
----------------
alexfh wrote:
> Repeating the whole message each time makes the test harder to read. Please
> leave the whole message once and shorten all other occurrences, e.g.:
>
> // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function declaration
Fixed
================
Comment at: test/clang-tidy/readability-remove-void-arg.cpp:145
@@ +144,3 @@
+// CHECK-FIXES: {{^}}typedef void (function_ptr2){{$}}
+// CHECK-FIXES-NEXT: {{^ }}({{$}}
+// CHECK-FIXES-NEXT: {{^ $}}
----------------
alexfh wrote:
> It would be more readable with a single regular expression:
> {{^ \($}}
Fixed.
http://reviews.llvm.org/D7639
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits