Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -741,24 +741,34 @@ /// matcher matches on it. bool matchesSpecialized(const Type &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { + + // DeducedType does not have declarations of its own, so + // match the deduced type instead. + const Type *EffectiveType = &Node; + if (const auto *S = dyn_cast(&Node)) { + EffectiveType = S->getDeducedType().getTypePtrOrNull(); + if (!EffectiveType) + return false; + } + // First, for any types that have a declaration, extract the declaration and // match on it. - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getInterface(), Finder, Builder); } @@ -770,14 +780,14 @@ // template struct X { T t; } class A {}; X a; // The following matcher will match, which otherwise would not: // fieldDecl(hasType(pointerType())). - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesSpecialized(S->getReplacementType(), Finder, Builder); } // For template specialization types, we want to match the template // declaration, as long as the type is still dependent, and otherwise the // declaration of the instantiated tag type. - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { if (!S->isTypeAlias() && S->isSugared()) { // If the template is non-dependent, we want to match the instantiated // tag type. @@ -796,7 +806,7 @@ // FIXME: We desugar elaborated types. This makes the assumption that users // do never want to match on whether a type is elaborated - there are // arguments for both sides; for now, continue desugaring. - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesSpecialized(S->desugar(), Finder, Builder); } return false; Index: test/clang-tidy/misc-use-after-move.cpp =================================================================== --- test/clang-tidy/misc-use-after-move.cpp +++ test/clang-tidy/misc-use-after-move.cpp @@ -723,6 +723,11 @@ std::move(container); container.clear(); container.empty(); + + auto container2 = container; + std::move(container2); + container2.clear(); + container2.empty(); } { std::deque container; Index: test/clang-tidy/performance-inefficient-string-concatenation.cpp =================================================================== --- test/clang-tidy/performance-inefficient-string-concatenation.cpp +++ test/clang-tidy/performance-inefficient-string-concatenation.cpp @@ -19,6 +19,8 @@ int main() { std::string mystr1, mystr2; std::wstring mywstr1, mywstr2; + auto myautostr1 = mystr1; + auto myautostr2 = mystr2; for (int i = 0; i < 10; ++i) { f(mystr1 + mystr2 + mystr1); @@ -33,6 +35,8 @@ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation mywstr1 = mywstr2 + mywstr2 + mywstr2; // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: string concatenation + myautostr1 = myautostr1 + myautostr2; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: string concatenation mywstr1 = mywstr2 + mywstr2; mystr1 = mystr2 + mystr2; Index: test/clang-tidy/readability-redundant-smartptr-get.cpp =================================================================== --- test/clang-tidy/readability-redundant-smartptr-get.cpp +++ test/clang-tidy/readability-redundant-smartptr-get.cpp @@ -97,6 +97,12 @@ // CHECK-MESSAGES: int i = *ip.get(); // CHECK-FIXES: int i = *ip; + auto ip2 = ip; + i = *ip2.get(); + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: redundant get() call + // CHECK-MESSAGES: i = *ip2.get(); + // CHECK-FIXES: i = *ip2; + std::unique_ptr uu; std::shared_ptr *ss; bool bb = uu.get() == nullptr; Index: test/clang-tidy/readability-uniqueptr-delete-release.cpp =================================================================== --- test/clang-tidy/readability-uniqueptr-delete-release.cpp +++ test/clang-tidy/readability-uniqueptr-delete-release.cpp @@ -24,6 +24,11 @@ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer '= nullptr' to 'delete x.release()' to reset unique_ptr<> objects [readability-uniqueptr-delete-release] // CHECK-FIXES: {{^}} P = nullptr; + auto P2 = P; + delete P2.release(); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer '= nullptr' to 'delete x.release()' to reset unique_ptr<> objects [readability-uniqueptr-delete-release] + // CHECK-FIXES: {{^}} P2 = nullptr; + std::unique_ptr Array[20]; delete Array[4].release(); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: prefer '= nullptr' to 'delete Index: unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1184,6 +1184,10 @@ EXPECT_TRUE(matches("int v[] = { 2, 3 }; void f() { for (int i : v) {} }", autoType())); + EXPECT_TRUE(matches("auto i = 2;", varDecl(hasType(isInteger())))); + EXPECT_TRUE(matches("struct X{}; auto x = X{};", + varDecl(hasType(recordDecl(hasName("X")))))); + // FIXME: Matching against the type-as-written can't work here, because the // type as written was not deduced. //EXPECT_TRUE(matches("auto a = 1;",