================
@@ -7,14 +7,78 @@
//===----------------------------------------------------------------------===//
#include "ContainerContainsCheck.h"
+#include "../utils/ASTUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang::ast_matchers;
namespace clang::tidy::readability {
+// Returns true if the macro body uses the parameter expanded at `ParamUseLoc`
+// only parenthesized or as the entire body, so every expansion parses alike.
+static bool isParameterUsedOnlyParenthesized(SourceLocation ParamUseLoc,
+ Preprocessor &PP,
+ const SourceManager &SM) {
+ const StringRef MacroName =
+ Lexer::getImmediateMacroName(ParamUseLoc, SM, PP.getLangOpts());
+ if (MacroName.empty())
+ return false;
+ const MacroInfo *MI =
+ PP.getMacroDefinitionAtLoc(PP.getIdentifierInfo(MacroName),
+ SM.getExpansionLoc(ParamUseLoc))
+ .getMacroInfo();
+ if (!MI)
+ return false;
+
+ const ArrayRef<Token> Tokens = MI->tokens();
+ const SourceLocation ParamDefLoc = SM.getSpellingLoc(ParamUseLoc);
+ const auto *ParamTok = llvm::find_if(Tokens, [ParamDefLoc](const Token &Tok)
{
+ return Tok.getLocation() == ParamDefLoc;
+ });
+ if (ParamTok == Tokens.end())
+ return false;
+ if (Tokens.size() == 1)
+ return true;
+
+ const IdentifierInfo *Param = ParamTok->getIdentifierInfo();
+ for (size_t I = 0, N = Tokens.size(); I < N; ++I) {
+ if (Tokens[I].getIdentifierInfo() != Param)
+ continue;
+ if (I == 0 || I + 1 == N || Tokens[I - 1].isNot(tok::l_paren) ||
+ Tokens[I + 1].isNot(tok::r_paren))
+ return false;
+ // Parentheses that may complete a call or a macro invocation, including
+ // one reached through a parameter or another expansion, do not group.
+ if (I >= 2 &&
+ Tokens[I - 2].isOneOf(tok::identifier, tok::r_paren, tok::r_square,
+ tok::r_brace, tok::greater, tok::greatergreater))
+ return false;
----------------
and2049 wrote:
I'm not sure whether the token-based rule in
`isParameterUsedOnlyParenthesized()` is too restrictive. I tried to avoid
changing how another expansion of the same argument is parsed, especially when
a macro callee comes through a parameter or another expansion, so this
withholds fixes for safe cases such as `((E) && f(E))` when `f` is an ordinary
function, and `E && E` when `E` is the boolean comparison.
https://github.com/llvm/llvm-project/pull/232196
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits