================
@@ -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

Reply via email to