EricWF created this revision.
EricWF added reviewers: fowles, rsmith, klimek.
Herald added a reviewer: shafik.

Currently the Clang AST doesn't store information about how the callee of a 
CallExpr was found. Specifically if it was found using ADL.

However, this information is invaluable to tooling. Consider a tool which 
renames usages of a function. If the originally CallExpr was formed using ADL, 
then the tooling may need to additionally qualify the replacement.
Without information about how the callee was found, the tooling is left 
scratching it's head. Additionally, we want to be able to match ADL calls as 
quickly as possible, which means avoiding computing the answer on the fly.

This patch changes `CallExpr` to store whether it's callee was found using ADL. 
It does not change the size of any AST nodes.


Repository:
  rC Clang

https://reviews.llvm.org/D55534

Files:
  include/clang/AST/Expr.h
  include/clang/AST/ExprCXX.h
  include/clang/AST/Stmt.h
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/Sema/Overload.h
  include/clang/Sema/Sema.h
  lib/AST/ASTDumper.cpp
  lib/AST/ASTImporter.cpp
  lib/AST/Expr.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  test/AST/ast-dump-expr.cpp
  unittests/ASTMatchers/ASTMatchersNodeTest.cpp

Index: unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -199,6 +199,32 @@
                                    "-fno-delayed-template-parsing"));
 }
 
+TEST(Matcher, ADLCall) {
+  StatementMatcher ADLMatch = callExpr(usesADL());
+  auto NS_Str = R"DELIM(
+  namespace NS {
+    struct X {};
+    struct Y {};
+    void f(X);
+    template <class T>
+    void g(T);
+  }
+  struct MyX {};
+  void f(...);
+  void g(...);
+)DELIM";
+
+  auto MkStr = [&](std::string Body) -> std::string {
+    std::string S = NS_Str;
+    S += "void test_fn() { " + Body + " }";
+    return S;
+  };
+
+  EXPECT_TRUE(matches(MkStr("NS::X x; f(x);"), ADLMatch));
+  EXPECT_TRUE(notMatches(MkStr("NS::X x; NS::f(x);"), ADLMatch));
+  EXPECT_TRUE(notMatches(MkStr("MyX x; f(x);"), ADLMatch));
+}
+
 TEST(Matcher, Call) {
   // FIXME: Do we want to overload Call() to directly take
   // Matcher<Decl>, too?
Index: test/AST/ast-dump-expr.cpp
===================================================================
--- /dev/null
+++ test/AST/ast-dump-expr.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-unused-value -std=c++14 -ast-dump %s \
+// RUN:    | FileCheck -strict-whitespace %s
+
+namespace NS {
+struct X {};
+void f(X);
+void y(...);
+} // namespace NS
+
+// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}ADLCall 'void ()'
+void ADLCall() {
+  NS::X x;
+  // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void' adl{{$}}
+  f(x);
+  // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void' adl{{$}}
+  y(x);
+}
+
+// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall 'void ()'
+void NonADLCall() {
+  NS::X x;
+  // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}}
+  NS::f(x);
+}
+
+// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall2 'void ()'
+void NonADLCall2() {
+  NS::X x;
+  using NS::f;
+  // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}}
+  f(x);
+  // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void' adl{{$}}
+  y(x);
+}
+
+namespace test_adl_call_three {
+using namespace NS;
+// CHECK-LABEL: FunctionDecl 0x{{[^ ]*}} {{.*}}NonADLCall3 'void ()'
+void NonADLCall3() {
+  X x;
+  // CHECK: CallExpr 0x{{[^ ]*}} <line:[[@LINE+1]]:{{[^>]+}}> 'void'{{$}}
+  f(x);
+}
+} // namespace test_adl_call_three
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -646,6 +646,7 @@
 void ASTStmtWriter::VisitCallExpr(CallExpr *E) {
   VisitExpr(E);
   Record.push_back(E->getNumArgs());
+  Record.push_back(E->usesADL());
   Record.AddSourceLocation(E->getRParenLoc());
   Record.AddStmt(E->getCallee());
   for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -732,11 +732,13 @@
 void ASTStmtReader::VisitCallExpr(CallExpr *E) {
   VisitExpr(E);
   unsigned NumArgs = Record.readInt();
+  bool UsesADL = Record.readInt();
   assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!");
   E->setRParenLoc(ReadSourceLocation());
   E->setCallee(Record.readSubExpr());
   for (unsigned I = 0; I != NumArgs; ++I)
     E->setArg(I, Record.readSubExpr());
+  E->setUsesADL(UsesADL);
 }
 
 void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -5946,15 +5946,13 @@
 /// \param PartialOverloading true if we are performing "partial" overloading
 /// based on an incomplete set of function arguments. This feature is used by
 /// code completion.
-void
-Sema::AddOverloadCandidate(FunctionDecl *Function,
-                           DeclAccessPair FoundDecl,
-                           ArrayRef<Expr *> Args,
-                           OverloadCandidateSet &CandidateSet,
-                           bool SuppressUserConversions,
-                           bool PartialOverloading,
-                           bool AllowExplicit,
-                           ConversionSequenceList EarlyConversions) {
+void Sema::AddOverloadCandidate(FunctionDecl *Function,
+                                DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
+                                OverloadCandidateSet &CandidateSet,
+                                bool SuppressUserConversions,
+                                bool PartialOverloading, bool AllowExplicit,
+                                bool IsADLCandidate,
+                                ConversionSequenceList EarlyConversions) {
   const FunctionProtoType *Proto
     = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
   assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6013,6 +6011,7 @@
   Candidate.Function = Function;
   Candidate.Viable = true;
   Candidate.IsSurrogate = false;
+  Candidate.IsADLCandidate = IsADLCandidate;
   Candidate.IgnoreObjectArgument = false;
   Candidate.ExplicitCallArguments = Args.size();
 
@@ -6715,14 +6714,11 @@
 /// Add a C++ function template specialization as a candidate
 /// in the candidate set, using template argument deduction to produce
 /// an appropriate function template specialization.
-void
-Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
-                                   DeclAccessPair FoundDecl,
-                                 TemplateArgumentListInfo *ExplicitTemplateArgs,
-                                   ArrayRef<Expr *> Args,
-                                   OverloadCandidateSet& CandidateSet,
-                                   bool SuppressUserConversions,
-                                   bool PartialOverloading) {
+void Sema::AddTemplateOverloadCandidate(
+    FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
+    TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
+    OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
+    bool PartialOverloading, bool IsADLCandidate) {
   if (!CandidateSet.isNewCandidate(FunctionTemplate))
     return;
 
@@ -6751,6 +6747,7 @@
     Candidate.Function = FunctionTemplate->getTemplatedDecl();
     Candidate.Viable = false;
     Candidate.IsSurrogate = false;
+    Candidate.IsADLCandidate = IsADLCandidate;
     // Ignore the object argument if there is one, since we don't have an object
     // type.
     Candidate.IgnoreObjectArgument =
@@ -6772,7 +6769,7 @@
   assert(Specialization && "Missing function template specialization?");
   AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet,
                        SuppressUserConversions, PartialOverloading,
-                       /*AllowExplicit*/false, Conversions);
+                       /*AllowExplicit*/ false, IsADLCandidate, Conversions);
 }
 
 /// Check that implicit conversion sequences can be formed for each argument
@@ -8935,16 +8932,19 @@
   // set.
   for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) {
     DeclAccessPair FoundDecl = DeclAccessPair::make(*I, AS_none);
+
     if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
       if (ExplicitTemplateArgs)
         continue;
 
       AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, false,
-                           PartialOverloading);
+                           PartialOverloading, /*AllowExplicit=*/false,
+                           /*IsADLCandidate=*/true);
     } else
-      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I),
-                                   FoundDecl, ExplicitTemplateArgs,
-                                   Args, CandidateSet, PartialOverloading);
+      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl,
+                                   ExplicitTemplateArgs, Args, CandidateSet,
+                                   /*SuppressUserConversions=*/false,
+                                   PartialOverloading, /*IsADLCandidate=*/true);
   }
 }
 
@@ -12021,7 +12021,8 @@
       return ExprError();
     Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
     return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc,
-                                         ExecConfig);
+                                         ExecConfig, /*IsExecConfig*/ false,
+                                         (*Best)->IsADLCandidate);
   }
 
   case OR_No_Viable_Function: {
@@ -12073,7 +12074,8 @@
     FunctionDecl *FDecl = (*Best)->Function;
     Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
     return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc,
-                                         ExecConfig);
+                                         ExecConfig, /*IsExecConfig*/ false,
+                                         (*Best)->IsADLCandidate);
   }
   }
 
@@ -12262,9 +12264,9 @@
       ResultTy = ResultTy.getNonLValueExprType(Context);
 
       Args[0] = Input;
-      CallExpr *TheCall =
-        new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(), ArgsArray,
-                                          ResultTy, VK, OpLoc, FPOptions());
+      CallExpr *TheCall = new (Context)
+          CXXOperatorCallExpr(Context, Op, FnExpr.get(), ArgsArray, ResultTy,
+                              VK, OpLoc, FPOptions(), Best->IsADLCandidate);
 
       if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
         return ExprError();
@@ -12494,10 +12496,9 @@
         ExprValueKind VK = Expr::getValueKindForType(ResultTy);
         ResultTy = ResultTy.getNonLValueExprType(Context);
 
-        CXXOperatorCallExpr *TheCall =
-          new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.get(),
-                                            Args, ResultTy, VK, OpLoc,
-                                            FPFeatures);
+        CXXOperatorCallExpr *TheCall = new (Context)
+            CXXOperatorCallExpr(Context, Op, FnExpr.get(), Args, ResultTy, VK,
+                                OpLoc, FPFeatures, Best->IsADLCandidate);
 
         if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
                                 FnDecl))
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -5585,12 +5585,11 @@
 /// block-pointer type.
 ///
 /// \param NDecl the declaration being called, if available
-ExprResult
-Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
-                            SourceLocation LParenLoc,
-                            ArrayRef<Expr *> Args,
-                            SourceLocation RParenLoc,
-                            Expr *Config, bool IsExecConfig) {
+ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
+                                       SourceLocation LParenLoc,
+                                       ArrayRef<Expr *> Args,
+                                       SourceLocation RParenLoc, Expr *Config,
+                                       bool IsExecConfig, bool UsesADL) {
   FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
   unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
 
@@ -5673,10 +5672,10 @@
   if (Config)
     TheCall = new (Context)
         CUDAKernelCallExpr(Context, Fn, cast<CallExpr>(Config), Args, ResultTy,
-                           VK_RValue, RParenLoc, NumParams);
+                           VK_RValue, RParenLoc, NumParams, UsesADL);
   else
-    TheCall = new (Context)
-        CallExpr(Context, Fn, Args, ResultTy, VK_RValue, RParenLoc, NumParams);
+    TheCall = new (Context) CallExpr(Context, Fn, Args, ResultTy, VK_RValue,
+                                     RParenLoc, NumParams, UsesADL);
 
   if (!getLangOpts().CPlusPlus) {
     // C cannot always handle TypoExpr nodes in builtin calls and direct
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1223,11 +1223,13 @@
 CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
                    ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
                    ExprValueKind VK, SourceLocation rparenloc,
-                   unsigned MinNumArgs)
+                   unsigned MinNumArgs, bool UsesADL)
     : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(),
            fn->isValueDependent(), fn->isInstantiationDependent(),
            fn->containsUnexpandedParameterPack()),
       RParenLoc(rparenloc) {
+  CallExprBits.UsesADL = UsesADL;
+
   NumArgs = std::max<unsigned>(args.size(), MinNumArgs);
   unsigned NumPreArgs = preargs.size();
   CallExprBits.NumPreArgs = NumPreArgs;
@@ -1249,25 +1251,27 @@
 
 CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
                    ArrayRef<Expr *> args, QualType t, ExprValueKind VK,
-                   SourceLocation rparenloc, unsigned MinNumArgs)
+                   SourceLocation rparenloc, unsigned MinNumArgs, bool UsesADL)
     : CallExpr(C, SC, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc,
-               MinNumArgs) {}
+               MinNumArgs, UsesADL) {}
 
 CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args,
                    QualType t, ExprValueKind VK, SourceLocation rparenloc,
-                   unsigned MinNumArgs)
-    : CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK,
-               rparenloc, MinNumArgs) {}
+                   unsigned MinNumArgs, bool UsesADL)
+    : CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc,
+               MinNumArgs, UsesADL) {}
 
 CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
-                   unsigned NumArgs, EmptyShell Empty)
+                   unsigned NumArgs, bool UsesADL, EmptyShell Empty)
     : Expr(SC, Empty), NumArgs(NumArgs) {
+  CallExprBits.UsesADL = UsesADL;
   CallExprBits.NumPreArgs = NumPreArgs;
   SubExprs = new (C) Stmt *[NumArgs + PREARGS_START + NumPreArgs];
 }
 
 CallExpr::CallExpr(const ASTContext &C, unsigned NumArgs, EmptyShell Empty)
-    : CallExpr(C, CallExprClass, /*NumPreArgs=*/0, NumArgs, Empty) {}
+    : CallExpr(C, CallExprClass, /*NumPreArgs=*/0, NumArgs, /*UsesADL=*/false,
+               Empty) {}
 
 void CallExpr::updateDependenciesFromArg(Expr *Arg) {
   if (Arg->isTypeDependent())
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -7380,7 +7380,7 @@
   if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) {
     return new (Importer.getToContext()) CXXOperatorCallExpr(
         Importer.getToContext(), OCE->getOperator(), ToCallee, ToArgs, ToType,
-        OCE->getValueKind(), ToRParenLoc, OCE->getFPFeatures());
+        OCE->getValueKind(), ToRParenLoc, OCE->getFPFeatures(), OCE->usesADL());
   }
 
   return new (Importer.getToContext()) CallExpr(
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -378,6 +378,7 @@
     void VisitOMPExecutableDirective(const OMPExecutableDirective *Node);
 
     // Exprs
+    void VisitCallExpr(const CallExpr *Node);
     void VisitCastExpr(const CastExpr *Node);
     void VisitImplicitCastExpr(const ImplicitCastExpr *Node);
     void VisitDeclRefExpr(const DeclRefExpr *Node);
@@ -1864,6 +1865,11 @@
   OS << ')';
 }
 
+void ASTDumper::VisitCallExpr(const CallExpr *Node) {
+  if (Node->usesADL())
+    OS << " adl";
+}
+
 void ASTDumper::VisitCastExpr(const CastExpr *Node) {
   OS << " <";
   {
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2749,13 +2749,13 @@
   typedef llvm::SmallSetVector<DeclContext   *, 16> AssociatedNamespaceSet;
   typedef llvm::SmallSetVector<CXXRecordDecl *, 16> AssociatedClassSet;
 
-  void AddOverloadCandidate(FunctionDecl *Function,
-                            DeclAccessPair FoundDecl,
+  void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl,
                             ArrayRef<Expr *> Args,
                             OverloadCandidateSet &CandidateSet,
                             bool SuppressUserConversions = false,
                             bool PartialOverloading = false,
                             bool AllowExplicit = false,
+                            bool IsADLCandidate = false,
                             ConversionSequenceList EarlyConversions = None);
   void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
                       ArrayRef<Expr *> Args,
@@ -2789,13 +2789,11 @@
                                   OverloadCandidateSet& CandidateSet,
                                   bool SuppressUserConversions = false,
                                   bool PartialOverloading = false);
-  void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
-                                    DeclAccessPair FoundDecl,
-                                 TemplateArgumentListInfo *ExplicitTemplateArgs,
-                                    ArrayRef<Expr *> Args,
-                                    OverloadCandidateSet& CandidateSet,
-                                    bool SuppressUserConversions = false,
-                                    bool PartialOverloading = false);
+  void AddTemplateOverloadCandidate(
+      FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
+      TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
+      OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
+      bool PartialOverloading = false, bool IsADLCandidate = false);
   bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
                                     ArrayRef<QualType> ParamTypes,
                                     ArrayRef<Expr *> Args,
@@ -4391,12 +4389,11 @@
                            MultiExprArg ArgExprs, SourceLocation RParenLoc,
                            Expr *ExecConfig = nullptr,
                            bool IsExecConfig = false);
-  ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
-                                   SourceLocation LParenLoc,
-                                   ArrayRef<Expr *> Arg,
-                                   SourceLocation RParenLoc,
-                                   Expr *Config = nullptr,
-                                   bool IsExecConfig = false);
+  ExprResult
+  BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc,
+                        ArrayRef<Expr *> Arg, SourceLocation RParenLoc,
+                        Expr *Config = nullptr, bool IsExecConfig = false,
+                        bool UsesADL = false);
 
   ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
                                      MultiExprArg ExecConfig,
Index: include/clang/Sema/Overload.h
===================================================================
--- include/clang/Sema/Overload.h
+++ include/clang/Sema/Overload.h
@@ -771,6 +771,9 @@
     /// object argument.
     bool IgnoreObjectArgument;
 
+    /// True if the candidate was found using ADL.
+    bool IsADLCandidate;
+
     /// FailureKind - The reason why this candidate is not viable.
     /// Actually an OverloadFailureKind.
     unsigned char FailureKind;
@@ -823,6 +826,11 @@
         return Function->getNumParams();
       return ExplicitCallArguments;
     }
+
+  private:
+    // Only the OverloadCandidate set is allowed to construct OverloadCandidates.
+    friend class OverloadCandidateSet;
+    OverloadCandidate() = default;
   };
 
   /// OverloadCandidateSet - A set of overload candidates, used in C++
@@ -945,6 +953,7 @@
 
       Candidates.push_back(OverloadCandidate());
       OverloadCandidate &C = Candidates.back();
+      C.IsADLCandidate = false;
       C.Conversions = Conversions.empty()
                           ? allocateConversionSequences(NumConversions)
                           : Conversions;
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -1257,6 +1257,26 @@
 /// \endcode
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> callExpr;
 
+/// Matches call expressions which were resolved using ADL.
+///
+/// Example matches y(x) but not y(42) or NS::y(x).
+/// \code
+///   namespace NS {
+///     struct X {};
+///     void y(X);
+///   } // namespace NS
+///
+///   void y(...);
+///
+///   void test() {
+///     NS::X x;
+///     y(x); // Matches
+///     NS::y(x); // Doesn't match
+///     y(42);
+///   }
+/// \endcode
+AST_MATCHER(CallExpr, usesADL) { return Node.usesADL(); }
+
 /// Matches lambda expressions.
 ///
 /// Example matches [&](){return 5;}
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -430,6 +430,9 @@
     unsigned : NumExprBits;
 
     unsigned NumPreArgs : 1;
+
+    /// True if the callee of the call expression was found using ADL.
+    unsigned UsesADL : 1;
   };
 
   class MemberExprBitfields {
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -90,10 +90,12 @@
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
 
-  CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
-                      ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
-                      SourceLocation operatorloc, FPOptions FPFeatures)
-      : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
+  CXXOperatorCallExpr(ASTContext &C, OverloadedOperatorKind Op, Expr *fn,
+                      ArrayRef<Expr *> args, QualType t, ExprValueKind VK,
+                      SourceLocation operatorloc, FPOptions FPFeatures,
+                      bool UsesADL = false)
+      : CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc,
+                 /*MinNumArgs=*/0, UsesADL),
         Operator(Op), FPFeatures(FPFeatures) {
     Range = getSourceRangeImpl();
   }
@@ -101,7 +103,7 @@
   explicit CXXOperatorCallExpr(ASTContext &C, unsigned NumArgs,
                                EmptyShell Empty)
       : CallExpr(C, CXXOperatorCallExprClass, /*NumPreArgs=*/0, NumArgs,
-                 Empty) {}
+                 /*UsesADL=*/false, Empty) {}
 
   /// Returns the kind of overloaded operator that this
   /// expression refers to.
@@ -168,10 +170,12 @@
   CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t,
                     ExprValueKind VK, SourceLocation RP,
                     unsigned MinNumArgs = 0)
-      : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP, MinNumArgs) {}
+      : CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP, MinNumArgs,
+                 /*UsesADL=*/false) {}
 
   CXXMemberCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty)
-      : CallExpr(C, CXXMemberCallExprClass, /*NumPreArgs=*/0, NumArgs, Empty) {}
+      : CallExpr(C, CXXMemberCallExprClass, /*NumPreArgs=*/0, NumArgs,
+                 /*UsesADL=*/false, Empty) {}
 
   /// Retrieves the implicit object argument for the member call.
   ///
@@ -210,13 +214,14 @@
 public:
   CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
                      ArrayRef<Expr *> args, QualType t, ExprValueKind VK,
-                     SourceLocation RP, unsigned MinNumArgs = 0)
+                     SourceLocation RP, unsigned MinNumArgs = 0,
+                     bool UsesADL = false)
       : CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP,
-                 MinNumArgs) {}
+                 MinNumArgs, UsesADL) {}
 
   CUDAKernelCallExpr(ASTContext &C, unsigned NumArgs, EmptyShell Empty)
       : CallExpr(C, CUDAKernelCallExprClass, /*NumPreArgs=*/END_PREARG, NumArgs,
-                 Empty) {}
+                 /*UsesADL=*/false, Empty) {}
 
   const CallExpr *getConfig() const {
     return cast_or_null<CallExpr>(getPreArg(CONFIG));
@@ -487,16 +492,17 @@
   friend class ASTStmtReader;
   friend class ASTStmtWriter;
 
-  UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
+  UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr *> Args,
                      QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
                      SourceLocation SuffixLoc)
-      : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc),
+      : CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc,
+                 /*MinNumArgs=*/0, /*UsesADL=*/false),
         UDSuffixLoc(SuffixLoc) {}
 
   explicit UserDefinedLiteral(const ASTContext &C, unsigned NumArgs,
                               EmptyShell Empty)
       : CallExpr(C, UserDefinedLiteralClass, /*NumPreArgs=*/0, NumArgs,
-                 Empty) {}
+                 /*UsesADL=*/false, Empty) {}
 
   /// The kind of literal operator which is invoked.
   enum LiteralOperatorKind {
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -2416,12 +2416,13 @@
   // These versions of the constructor are for derived classes.
   CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
            ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
-           ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0);
+           ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0,
+           bool UsesADL = false);
   CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args,
            QualType t, ExprValueKind VK, SourceLocation rparenloc,
-           unsigned MinNumArgs = 0);
+           unsigned MinNumArgs = 0, bool UsesADL = false);
   CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
-           unsigned NumArgs, EmptyShell Empty);
+           unsigned NumArgs, bool UsesADL, EmptyShell Empty);
 
   Stmt *getPreArg(unsigned i) {
     assert(i < getNumPreArgs() && "Prearg access out of range!");
@@ -2443,7 +2444,8 @@
   /// arguments. The actual number of arguments will be the greater of
   /// args.size() and MinNumArgs.
   CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t,
-           ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0);
+           ExprValueKind VK, SourceLocation rparenloc, unsigned MinNumArgs = 0,
+           bool UsesADL = false);
 
   /// Build an empty call expression.
   CallExpr(const ASTContext &C, unsigned NumArgs, EmptyShell Empty);
@@ -2452,6 +2454,9 @@
   Expr *getCallee() { return cast<Expr>(SubExprs[FN]); }
   void setCallee(Expr *F) { SubExprs[FN] = F; }
 
+  bool usesADL() const { return CallExprBits.UsesADL; }
+  void setUsesADL(bool V = true) { CallExprBits.UsesADL = V; }
+
   Decl *getCalleeDecl();
   const Decl *getCalleeDecl() const {
     return const_cast<CallExpr*>(this)->getCalleeDecl();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to