ziqingluo-90 updated this revision to Diff 519958. ziqingluo-90 marked an inline comment as done.
CHANGES SINCE LAST ACTION https://reviews.llvm.org/D146342/new/ https://reviews.llvm.org/D146342 Files: clang/include/clang/Sema/AnalysisBasedWarnings.h clang/lib/Sema/AnalysisBasedWarnings.cpp clang/lib/Sema/Sema.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-objc-method-traversal.mm clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp
Index: clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp @@ -220,11 +220,11 @@ void testTemplate(int * p) { int *a[10]; foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}} - // expected-note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}} + // FIXME: expected note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}} const int **q = const_cast<const int **>(&p); - testPointerArithmetic(p, q, p); //expected-note{{in instantiation of}} + testPointerArithmetic(p, q, p); //FIXME: expected note{{in instantiation of}} } void testPointerToMember() { @@ -315,7 +315,7 @@ foo(ar[5]); // expected-note{{used in buffer access here}} } -template void fArr<int>(int t[]); // expected-note {{in instantiation of}} +template void fArr<int>(int t[]); // FIXME: expected note {{in instantiation of}} int testReturn(int t[]) { // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-objc-method-traversal.mm =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-objc-method-traversal.mm @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++20 -Wno-objc-root-class -Wno-return-type -Wunsafe-buffer-usage %s -verify %s + +// This test is to show that ObjC methods are traversed by the +// end-of-TU analysis properly. Particularly, a method body will not +// be repeatedly visited whenever a method prototype of it is visited. + +@interface I ++ f:(int *) p; // duplicated method prototype declaration + ++ f:(int *) p; + ++ f:(int *) p; +@end + +@implementation I ++ f:(int *) p { // expected-warning{{'p' is an unsafe pointer used for buffer access}} + int tmp; + tmp = p[5]; // expected-note{{used in buffer access here}} +} +@end Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -1426,6 +1426,8 @@ } } + AnalysisWarnings.IssueWarnings(Context.getTranslationUnitDecl()); + // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" @@ -25,6 +26,8 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Type.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/Analyses/CalledOnceCheck.h" #include "clang/Analysis/Analyses/Consumed.h" @@ -2290,6 +2293,111 @@ S.Diag(D.Loc, D.PD); } +void clang::sema::AnalysisBasedWarnings::IssueWarnings( + const TranslationUnitDecl *TU) { + if (!TU) + return; // This is unexpected, give up quietly. + + DiagnosticsEngine &Diags = S.getDiagnostics(); + const bool EmitFixits = + Diags.getDiagnosticOptions().ShowFixits && S.getLangOpts().CPlusPlus20; + + if (S.hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings()) + // exit if having uncompilable errors or ignoring all warnings: + return; + + // An AST Visitor that calls analyzers on each callable definition: + class CallableVisitor : public RecursiveASTVisitor<CallableVisitor> { + private: + Sema &S; + const bool EmitFixits; + // Will be set to true iff visiting a `LambdaExpr`: + bool IsVisitingLambda = false; + + public: + CallableVisitor(Sema &S, bool EmitFixits) : S(S), EmitFixits(EmitFixits) {} + + bool TraverseDecl(Decl *Node) { + if (!Node) + return true; + + // Do not analyze any `Decl` if we are going to just ignore them. + DiagnosticsEngine &Diags = S.getDiagnostics(); + + if (Diags.getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(Node->getLocation())) + return true; + // Continue to traverse descendants: + return RecursiveASTVisitor::TraverseDecl(Node); + } + + bool VisitFunctionDecl(FunctionDecl *Node) { + if (cast<DeclContext>(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + // `FunctionDecl->hasBody()` returns true if the function has a body + // somewhere defined. But we want to know if this `Node` has a body + // child. So we use `doesThisDeclarationHaveABody`: + if (Node->doesThisDeclarationHaveABody()) { + UnsafeBufferUsageReporter R(S); + + checkUnsafeBufferUsage(Node, R, EmitFixits); + } + return true; + } + + bool VisitBlockDecl(BlockDecl *Node) { + if (cast<DeclContext>(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + + UnsafeBufferUsageReporter R(S); + + checkUnsafeBufferUsage(Node, R, EmitFixits); + return true; + } + + bool VisitObjCMethodDecl(ObjCMethodDecl *Node) { + if (cast<DeclContext>(Node)->isDependentContext()) + return true; // Not to analyze dependent decl + if (Node->hasBody()) { + UnsafeBufferUsageReporter R(S); + + checkUnsafeBufferUsage(Node, R, EmitFixits); + } + return true; + } + + bool TraverseStmt(Stmt *Node, DataRecursionQueue *Queue = nullptr) { + if (!Node) + return true; + if (isa<LambdaExpr>(Node)) { + // to visit implicit children of `LambdaExpr`s: + IsVisitingLambda = true; + + bool Result = RecursiveASTVisitor::TraverseStmt(Node); + + IsVisitingLambda = false; // set the flag back + return Result; + } + return RecursiveASTVisitor::TraverseStmt(Node); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { + // The function declaration representing a lambda is implicit and we want + // to visit it: + return IsVisitingLambda; + } + }; + + // Emit unsafe buffer usage warnings and fixits. + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) || + !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation())) { + CallableVisitor(S, EmitFixits) + .TraverseTranslationUnitDecl( + std::remove_const_t<TranslationUnitDecl *>(TU)); + } +} + void clang::sema::AnalysisBasedWarnings::IssueWarnings( sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope, const Decl *D, QualType BlockType) { @@ -2518,16 +2626,6 @@ if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD)) checkThrowInNonThrowingFunc(S, FD, AC); - // Emit unsafe buffer usage warnings and fixits. - if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) { - UnsafeBufferUsageReporter R(S); - checkUnsafeBufferUsage( - D, R, - /*EmitFixits=*/S.getDiagnostics().getDiagnosticOptions().ShowFixits && - S.getLangOpts().CPlusPlus20); - } - // If none of the previous checks caused a CFG build, trigger one here // for the logical error handler. if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { Index: clang/include/clang/Sema/AnalysisBasedWarnings.h =================================================================== --- clang/include/clang/Sema/AnalysisBasedWarnings.h +++ clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H #define LLVM_CLANG_SEMA_ANALYSISBASEDWARNINGS_H +#include "clang/AST/Decl.h" #include "llvm/ADT/DenseMap.h" #include <memory> @@ -95,6 +96,9 @@ void IssueWarnings(Policy P, FunctionScopeInfo *fscope, const Decl *D, QualType BlockType); + // Issue warnings that require whole-translation-unit analysis. + void IssueWarnings(const TranslationUnitDecl *D); + Policy getDefaultPolicy() { return DefaultPolicy; } void PrintStats() const;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits