[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
https://github.com/ymand closed https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
https://github.com/bazuzi updated https://github.com/llvm/llvm-project/pull/88754 >From 223d4c48abf27c8b0949ac1520b66ef32cbd63c1 Mon Sep 17 00:00:00 2001 From: Samira Bazuzi Date: Fri, 12 Apr 2024 12:18:44 -0400 Subject: [PATCH 1/4] [clang][dataflow] Expose fields, globals, and functions referenced. Exposes the collection functionality, but does not alter it beyond using a return value instead of output parameters. Also relocates underlying and related functions and a class from DataflowEnvironment's files to DataflowAnalysisContext's files, as no Environment is needed. --- .../FlowSensitive/DataflowAnalysisContext.h | 46 + .../FlowSensitive/DataflowEnvironment.h | 36 .../FlowSensitive/DataflowAnalysisContext.cpp | 174 + .../FlowSensitive/DataflowEnvironment.cpp | 176 +- clang/lib/Analysis/FlowSensitive/Transfer.cpp | 1 + 5 files changed, 225 insertions(+), 208 deletions(-) diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index 909a91059438ca..a34e5f603eb396 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -62,6 +62,52 @@ FieldSet getObjectFields(QualType Type); bool containsSameFields(const FieldSet , const RecordStorageLocation::FieldToLoc ); +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +/// Helper class for initialization of a record with an `InitListExpr`. +/// `InitListExpr::inits()` contains the initializers for both the base classes +/// and the fields of the record; this helper class separates these out into two +/// different lists. In addition, it deals with special cases associated with +/// unions. +class RecordInitListHelper { +public: + // `InitList` must have record type. + RecordInitListHelper(const InitListExpr *InitList); + + // Base classes with their associated initializer expressions. + ArrayRef> base_inits() const { +return BaseInits; + } + + // Fields with their associated initializer expressions. + ArrayRef> field_inits() const { +return FieldInits; + } + +private: + SmallVector> BaseInits; + SmallVector> FieldInits; + + // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a + // member variable because we store a pointer to it in `FieldInits`. + std::optional ImplicitValueInitForUnion; +}; + +struct FieldsGlobalsAndFuncs { + FieldSet Fields; + // Globals includes all variables with global storage, notably including + // static data members and static variables declared within a function. + llvm::DenseSet Globals; + llvm::DenseSet Funcs; +}; + +FieldsGlobalsAndFuncs getFieldsGlobalsAndFuncs(const FunctionDecl ); + struct ContextSensitiveOptions { /// The maximum depth to analyze. A value of zero is equivalent to disabling /// context-sensitive analysis entirely. diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 706664d7db1c25..4277792219c0af 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -775,42 +775,6 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr , RecordStorageLocation *getBaseObjectLocation(const MemberExpr , const Environment ); -/// Returns the fields of a `RecordDecl` that are initialized by an -/// `InitListExpr`, in the order in which they appear in -/// `InitListExpr::inits()`. -/// `Init->getType()` must be a record type. -std::vector -getFieldsForInitListExpr(const InitListExpr *InitList); - -/// Helper class for initialization of a record with an `InitListExpr`. -/// `InitListExpr::inits()` contains the initializers for both the base classes -/// and the fields of the record; this helper class separates these out into two -/// different lists. In addition, it deals with special cases associated with -/// unions. -class RecordInitListHelper { -public: - // `InitList` must have record type. - RecordInitListHelper(const InitListExpr *InitList); - - // Base classes with their associated initializer expressions. - ArrayRef> base_inits() const { -return BaseInits; - } - - // Fields with their associated initializer expressions. - ArrayRef> field_inits() const { -return FieldInits; - } - -private: - SmallVector> BaseInits; - SmallVector> FieldInits; - - // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a - // member variable because we store a pointer to it in
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,75 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +namespace dataflow { +/// Skip past nodes that the CFG does not emit. These nodes are invisible to +/// flow-sensitive analysis, and should be ignored as they will effectively not +/// exist. +/// +/// * `ParenExpr` - The CFG takes the operator precedence into account, but +/// otherwise omits the node afterwards. +/// +/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to +/// destructors and then omit the node. +/// +const Expr (const Expr ); +const Stmt (const Stmt ); + +/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic +/// iteration order. +using FieldSet = llvm::SmallSetVector; + +/// Returns the set of all fields in the type. +FieldSet getObjectFields(QualType Type); + +/// Returns whether `Fields` and `FieldLocs` contain the same fields. +bool containsSameFields(const FieldSet , +const RecordStorageLocation::FieldToLoc ); + +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +// A collection of several types of declarations, all referenced from the same +// function. +struct ReferencedDecls { + // Fields includes non-static data members. + FieldSet Fields; + // Globals includes all variables with global storage, notably including + // static data members and static variables declared within a function. + llvm::DenseSet Globals; + // Functions includes free functions and member functions which are + // referenced, but not necessarily called. + llvm::DenseSet Functions; +}; + +/// Collects and returns fields, global variables and functions that are +/// declared in or referenced from `FD`. martinboehme wrote: ```suggestion /// Returns declarations that are declared in or referenced from `FD`. ``` https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,75 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +namespace dataflow { +/// Skip past nodes that the CFG does not emit. These nodes are invisible to martinboehme wrote: ```suggestion namespace dataflow { /// Skip past nodes that the CFG does not emit. These nodes are invisible to ``` This is the usual style in the project. (Otherwise, the namespace looks as if it belongs more closely to the following function than that function belongs to the others.) https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,214 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#include "clang/Analysis/FlowSensitive/ASTOps.h" +#include "clang/AST/ComputeDependence.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include +#include +#include + +#define DEBUG_TYPE "dataflow" + +namespace clang::dataflow { +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList) { + const RecordDecl *RD = InitList->getType()->getAsRecordDecl(); + assert(RD != nullptr); + + std::vector Fields; + + if (InitList->getType()->isUnionType()) { +Fields.push_back(InitList->getInitializedFieldInUnion()); +return Fields; + } + + // Unnamed bitfields are only used for padding and do not appear in + // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s + // field list, and we thus need to remove them before mapping inits to + // fields to avoid mapping inits to the wrongs fields. + llvm::copy_if( + RD->fields(), std::back_inserter(Fields), + [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); }); + return Fields; +} + +static void insertIfGlobal(const Decl , + llvm::DenseSet ) { + if (auto *V = dyn_cast()) +if (V->hasGlobalStorage()) + Vars.insert(V); +} + +static void insertIfFunction(const Decl , + llvm::DenseSet ) { + if (auto *FD = dyn_cast()) +Funcs.insert(FD); +} + +static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr ) { + // Use getCalleeDecl instead of getMethodDecl in order to handle + // pointer-to-member calls. + const auto *MethodDecl = dyn_cast_or_null(C.getCalleeDecl()); + if (!MethodDecl) +return nullptr; + auto *Body = dyn_cast_or_null(MethodDecl->getBody()); + if (!Body || Body->size() != 1) +return nullptr; + if (auto *RS = dyn_cast(*Body->body_begin())) +if (auto *Return = RS->getRetValue()) + return dyn_cast(Return->IgnoreParenImpCasts()); + return nullptr; +} + +static void getReferencedDecls(const Decl , FieldSet , + llvm::DenseSet , + llvm::DenseSet ) { martinboehme wrote: Suggest a `ReferencedDecls` parameter instead of passing `Fields`, `Vars`, and `Funcs` separately. ```suggestion static void getReferencedDecls(const Decl , ReferencedDecls ) { ``` https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -66,6 +66,35 @@ inline bool recordsEqual(const RecordStorageLocation , return recordsEqual(Loc1, Env, Loc2, Env); } +/// Helper class for initialization of a record with an `InitListExpr`. +/// `InitListExpr::inits()` contains the initializers for both the base classes +/// and the fields of the record; this helper class separates these out into two +/// different lists. In addition, it deals with special cases associated with +/// unions. +class RecordInitListHelper { +public: + // `InitList` must have record type. + RecordInitListHelper(const InitListExpr *InitList); + + // Base classes with their associated initializer expressions. + ArrayRef> base_inits() const { +return BaseInits; + } + + // Fields with their associated initializer expressions. + ArrayRef> field_inits() const { +return FieldInits; + } + +private: + SmallVector> BaseInits; + SmallVector> FieldInits; + + // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a + // member variable because we store a pointer to it in `FieldInits`. + std::optional ImplicitValueInitForUnion; +}; + martinboehme wrote: I think this would fit better in ASTOps.h as well. The intent of RecordOps.h is to contain functions that operate on our representation of record objects, i.e. `RecordStorageLocation`s. `RecordInitListHelper`, on the other hand, is just a more convenient way of accessing the initializers in an `InitListExpr` and so seems a better fit in ASTOps.h. (Note also that the closely related `getFieldsForInitListExpr()` already lives there.) https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -648,36 +563,13 @@ void Environment::initialize() { void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { assert(FuncDecl->doesThisDeclarationHaveABody()); - FieldSet Fields; - llvm::DenseSet Vars; - llvm::DenseSet Funcs; - - // Look for global variable and field references in the - // constructor-initializers. - if (const auto *CtorDecl = dyn_cast(FuncDecl)) { -for (const auto *Init : CtorDecl->inits()) { - if (Init->isMemberInitializer()) { -Fields.insert(Init->getMember()); - } else if (Init->isIndirectMemberInitializer()) { -for (const auto *I : Init->getIndirectMember()->chain()) - Fields.insert(cast(I)); - } - const Expr *E = Init->getInit(); - assert(E != nullptr); - getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs); -} -// Add all fields mentioned in default member initializers. -for (const FieldDecl *F : CtorDecl->getParent()->fields()) - if (const auto *I = F->getInClassInitializer()) - getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs); - } - getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs); + ReferencedDecls FGF = getReferencedDecls(*FuncDecl); martinboehme wrote: ```suggestion ReferencedDecls Referenced = getReferencedDecls(*FuncDecl); ``` (Now that the struct is called `ReferencedDecls`, it's not clear why the variable should be called `FGF`.) https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
martinboehme wrote: Can you add this file to clang/docs/tools/clang-formatted-files.txt? https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
https://github.com/martinboehme approved this pull request. Thanks for the cleanup! https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,214 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#include "clang/Analysis/FlowSensitive/ASTOps.h" +#include "clang/AST/ComputeDependence.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include +#include +#include + +#define DEBUG_TYPE "dataflow" + +namespace clang::dataflow { +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList) { + const RecordDecl *RD = InitList->getType()->getAsRecordDecl(); + assert(RD != nullptr); + + std::vector Fields; + + if (InitList->getType()->isUnionType()) { +Fields.push_back(InitList->getInitializedFieldInUnion()); +return Fields; + } + + // Unnamed bitfields are only used for padding and do not appear in + // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s + // field list, and we thus need to remove them before mapping inits to + // fields to avoid mapping inits to the wrongs fields. + llvm::copy_if( + RD->fields(), std::back_inserter(Fields), + [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); }); + return Fields; +} + +static void insertIfGlobal(const Decl , + llvm::DenseSet ) { + if (auto *V = dyn_cast()) +if (V->hasGlobalStorage()) + Vars.insert(V); +} + +static void insertIfFunction(const Decl , + llvm::DenseSet ) { + if (auto *FD = dyn_cast()) +Funcs.insert(FD); +} + +static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr ) { + // Use getCalleeDecl instead of getMethodDecl in order to handle + // pointer-to-member calls. + const auto *MethodDecl = dyn_cast_or_null(C.getCalleeDecl()); + if (!MethodDecl) +return nullptr; + auto *Body = dyn_cast_or_null(MethodDecl->getBody()); + if (!Body || Body->size() != 1) +return nullptr; + if (auto *RS = dyn_cast(*Body->body_begin())) +if (auto *Return = RS->getRetValue()) + return dyn_cast(Return->IgnoreParenImpCasts()); + return nullptr; +} + +static void getReferencedDecls(const Decl , FieldSet , + llvm::DenseSet , + llvm::DenseSet ) { + insertIfGlobal(D, Vars); + insertIfFunction(D, Funcs); + if (const auto *Decomp = dyn_cast()) +for (const auto *B : Decomp->bindings()) + if (auto *ME = dyn_cast_or_null(B->getBinding())) +// FIXME: should we be using `E->getFoundDecl()`? +if (const auto *FD = dyn_cast(ME->getMemberDecl())) + Fields.insert(FD); +} + +/// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields, +/// global variables and functions that are declared in or referenced from +/// sub-statements. +static void getReferencedDecls(const Stmt , FieldSet , martinboehme wrote: Again, suggest a `ReferencedDecls` parameter. This would also make the multiple recursive calls less verbose. https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,214 @@ +//===-- ASTOps.h ---*- C++ -*-===// martinboehme wrote: ```suggestion //===-- ASTOps.cpp -*- C++ -*-===// ``` https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,75 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +namespace dataflow { +/// Skip past nodes that the CFG does not emit. These nodes are invisible to +/// flow-sensitive analysis, and should be ignored as they will effectively not +/// exist. +/// +/// * `ParenExpr` - The CFG takes the operator precedence into account, but +/// otherwise omits the node afterwards. +/// +/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to +/// destructors and then omit the node. +/// +const Expr (const Expr ); +const Stmt (const Stmt ); + +/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic +/// iteration order. +using FieldSet = llvm::SmallSetVector; + +/// Returns the set of all fields in the type. +FieldSet getObjectFields(QualType Type); + +/// Returns whether `Fields` and `FieldLocs` contain the same fields. +bool containsSameFields(const FieldSet , +const RecordStorageLocation::FieldToLoc ); + +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +// A collection of several types of declarations, all referenced from the same +// function. +struct ReferencedDecls { + // Fields includes non-static data members. + FieldSet Fields; + // Globals includes all variables with global storage, notably including + // static data members and static variables declared within a function. + llvm::DenseSet Globals; + // Functions includes free functions and member functions which are + // referenced, but not necessarily called. martinboehme wrote: ```suggestion // Free functions and member functions which are referenced (but not necessarily called). ``` https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,75 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +namespace dataflow { +/// Skip past nodes that the CFG does not emit. These nodes are invisible to +/// flow-sensitive analysis, and should be ignored as they will effectively not +/// exist. +/// +/// * `ParenExpr` - The CFG takes the operator precedence into account, but +/// otherwise omits the node afterwards. +/// +/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to +/// destructors and then omit the node. +/// +const Expr (const Expr ); +const Stmt (const Stmt ); + +/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic +/// iteration order. +using FieldSet = llvm::SmallSetVector; + +/// Returns the set of all fields in the type. +FieldSet getObjectFields(QualType Type); + +/// Returns whether `Fields` and `FieldLocs` contain the same fields. +bool containsSameFields(const FieldSet , +const RecordStorageLocation::FieldToLoc ); + +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +// A collection of several types of declarations, all referenced from the same +// function. +struct ReferencedDecls { + // Fields includes non-static data members. martinboehme wrote: ```suggestion /// Non-static member variables. ``` * Make this a Doxygen comment (three slashes) * No need to repeat the name of the declaration you're documenting * "includes" could be interpreted as "in addition to something else, includes non-static data members", so just dropping it. * Standard C++ terminology is "member variables" https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,75 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +namespace dataflow { +/// Skip past nodes that the CFG does not emit. These nodes are invisible to +/// flow-sensitive analysis, and should be ignored as they will effectively not +/// exist. +/// +/// * `ParenExpr` - The CFG takes the operator precedence into account, but +/// otherwise omits the node afterwards. +/// +/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to +/// destructors and then omit the node. +/// +const Expr (const Expr ); +const Stmt (const Stmt ); + +/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic +/// iteration order. +using FieldSet = llvm::SmallSetVector; + +/// Returns the set of all fields in the type. +FieldSet getObjectFields(QualType Type); + +/// Returns whether `Fields` and `FieldLocs` contain the same fields. +bool containsSameFields(const FieldSet , +const RecordStorageLocation::FieldToLoc ); + +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +// A collection of several types of declarations, all referenced from the same +// function. +struct ReferencedDecls { + // Fields includes non-static data members. + FieldSet Fields; + // Globals includes all variables with global storage, notably including + // static data members and static variables declared within a function. + llvm::DenseSet Globals; + // Functions includes free functions and member functions which are + // referenced, but not necessarily called. + llvm::DenseSet Functions; +}; + +/// Collects and returns fields, global variables and functions that are +/// declared in or referenced from `FD`. +ReferencedDecls getReferencedDecls(const FunctionDecl ); +} // namespace dataflow martinboehme wrote: ```suggestion ReferencedDecls getReferencedDecls(const FunctionDecl ); } // namespace dataflow ``` https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
martinboehme wrote: Can you add this file to clang/docs/tools/clang-formatted-files.txt? https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
@@ -0,0 +1,75 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +namespace dataflow { +/// Skip past nodes that the CFG does not emit. These nodes are invisible to +/// flow-sensitive analysis, and should be ignored as they will effectively not +/// exist. +/// +/// * `ParenExpr` - The CFG takes the operator precedence into account, but +/// otherwise omits the node afterwards. +/// +/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to +/// destructors and then omit the node. +/// +const Expr (const Expr ); +const Stmt (const Stmt ); + +/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic +/// iteration order. +using FieldSet = llvm::SmallSetVector; + +/// Returns the set of all fields in the type. +FieldSet getObjectFields(QualType Type); + +/// Returns whether `Fields` and `FieldLocs` contain the same fields. +bool containsSameFields(const FieldSet , +const RecordStorageLocation::FieldToLoc ); + +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +// A collection of several types of declarations, all referenced from the same +// function. +struct ReferencedDecls { + // Fields includes non-static data members. + FieldSet Fields; + // Globals includes all variables with global storage, notably including + // static data members and static variables declared within a function. martinboehme wrote: ```suggestion // All variables with static storage duration, notably including static member variables and static // variables declared within a function. ``` https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
https://github.com/martinboehme edited https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
https://github.com/ymand approved this pull request. Thanks! https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
bazuzi wrote: @ymand @martinboehme Apologies for the broken chains of comments; can you take another look? https://github.com/llvm/llvm-project/pull/88754 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
llvmbot wrote: @llvm/pr-subscribers-clang-analysis Author: Samira Bazuzi (bazuzi) Changes Moves free functions from DataflowEnvironment.h/cc and DataflowAnalysisContext.h/cc to RecordOps and a new ASTOps and exposes them as needed for current use and to expose getReferencedDecls for out-of-tree use. Minimal change in functionality, only to modify the return type of getReferenceDecls to return the collected decls instead of using output params. Tested with `ninja check-clang-tooling`. This started as #88534, but I screwed up the push of changes after a first round of comments and needed to close that PR to avoid spam for recent commit authors. I believe all of the first round comments have been addressed and should be considered marked "Done" and resolved. --- Patch is 31.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/88754.diff 10 Files Affected: - (added) clang/include/clang/Analysis/FlowSensitive/ASTOps.h (+75) - (modified) clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h (+1-27) - (modified) clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h (-36) - (modified) clang/include/clang/Analysis/FlowSensitive/RecordOps.h (+29) - (added) clang/lib/Analysis/FlowSensitive/ASTOps.cpp (+214) - (modified) clang/lib/Analysis/FlowSensitive/CMakeLists.txt (+1) - (modified) clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp (+1-52) - (modified) clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (+6-172) - (modified) clang/lib/Analysis/FlowSensitive/RecordOps.cpp (+37) - (modified) clang/lib/Analysis/FlowSensitive/Transfer.cpp (+2) ``diff diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h new file mode 100644 index 00..5e3c0f21f5e863 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h @@ -0,0 +1,75 @@ +//===-- ASTOps.h ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// Operations on AST nodes that are used in flow-sensitive analysis. +// +//===--===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/FlowSensitive/StorageLocation.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +namespace dataflow { +/// Skip past nodes that the CFG does not emit. These nodes are invisible to +/// flow-sensitive analysis, and should be ignored as they will effectively not +/// exist. +/// +/// * `ParenExpr` - The CFG takes the operator precedence into account, but +/// otherwise omits the node afterwards. +/// +/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to +/// destructors and then omit the node. +/// +const Expr (const Expr ); +const Stmt (const Stmt ); + +/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic +/// iteration order. +using FieldSet = llvm::SmallSetVector; + +/// Returns the set of all fields in the type. +FieldSet getObjectFields(QualType Type); + +/// Returns whether `Fields` and `FieldLocs` contain the same fields. +bool containsSameFields(const FieldSet , +const RecordStorageLocation::FieldToLoc ); + +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +// A collection of several types of declarations, all referenced from the same +// function. +struct ReferencedDecls { + // Fields includes non-static data members. + FieldSet Fields; + // Globals includes all variables with global storage, notably including + // static data members and static variables declared within a function. + llvm::DenseSet Globals; + // Functions includes free functions and member functions which are + // referenced, but not necessarily called. + llvm::DenseSet Functions; +}; + +/// Collects and returns fields, global variables and functions that are +/// declared in or referenced from `FD`. +ReferencedDecls getReferencedDecls(const FunctionDecl ); +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index
[clang] [clang][dataflow] Expose getReferencedDecls and relocate free functions. (PR #88754)
https://github.com/bazuzi created https://github.com/llvm/llvm-project/pull/88754 Moves free functions from DataflowEnvironment.h/cc and DataflowAnalysisContext.h/cc to RecordOps and a new ASTOps and exposes them as needed for current use and to expose getReferencedDecls for out-of-tree use. Minimal change in functionality, only to modify the return type of getReferenceDecls to return the collected decls instead of using output params. Tested with `ninja check-clang-tooling`. This started as #88534, but I screwed up the push of changes after a first round of comments and needed to close that PR to avoid spam for recent commit authors. I believe all of the first round comments have been addressed and should be considered marked "Done" and resolved. >From 223d4c48abf27c8b0949ac1520b66ef32cbd63c1 Mon Sep 17 00:00:00 2001 From: Samira Bazuzi Date: Fri, 12 Apr 2024 12:18:44 -0400 Subject: [PATCH 1/3] [clang][dataflow] Expose fields, globals, and functions referenced. Exposes the collection functionality, but does not alter it beyond using a return value instead of output parameters. Also relocates underlying and related functions and a class from DataflowEnvironment's files to DataflowAnalysisContext's files, as no Environment is needed. --- .../FlowSensitive/DataflowAnalysisContext.h | 46 + .../FlowSensitive/DataflowEnvironment.h | 36 .../FlowSensitive/DataflowAnalysisContext.cpp | 174 + .../FlowSensitive/DataflowEnvironment.cpp | 176 +- clang/lib/Analysis/FlowSensitive/Transfer.cpp | 1 + 5 files changed, 225 insertions(+), 208 deletions(-) diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index 909a91059438ca..a34e5f603eb396 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -62,6 +62,52 @@ FieldSet getObjectFields(QualType Type); bool containsSameFields(const FieldSet , const RecordStorageLocation::FieldToLoc ); +/// Returns the fields of a `RecordDecl` that are initialized by an +/// `InitListExpr`, in the order in which they appear in +/// `InitListExpr::inits()`. +/// `Init->getType()` must be a record type. +std::vector +getFieldsForInitListExpr(const InitListExpr *InitList); + +/// Helper class for initialization of a record with an `InitListExpr`. +/// `InitListExpr::inits()` contains the initializers for both the base classes +/// and the fields of the record; this helper class separates these out into two +/// different lists. In addition, it deals with special cases associated with +/// unions. +class RecordInitListHelper { +public: + // `InitList` must have record type. + RecordInitListHelper(const InitListExpr *InitList); + + // Base classes with their associated initializer expressions. + ArrayRef> base_inits() const { +return BaseInits; + } + + // Fields with their associated initializer expressions. + ArrayRef> field_inits() const { +return FieldInits; + } + +private: + SmallVector> BaseInits; + SmallVector> FieldInits; + + // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a + // member variable because we store a pointer to it in `FieldInits`. + std::optional ImplicitValueInitForUnion; +}; + +struct FieldsGlobalsAndFuncs { + FieldSet Fields; + // Globals includes all variables with global storage, notably including + // static data members and static variables declared within a function. + llvm::DenseSet Globals; + llvm::DenseSet Funcs; +}; + +FieldsGlobalsAndFuncs getFieldsGlobalsAndFuncs(const FunctionDecl ); + struct ContextSensitiveOptions { /// The maximum depth to analyze. A value of zero is equivalent to disabling /// context-sensitive analysis entirely. diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 706664d7db1c25..4277792219c0af 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -775,42 +775,6 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr , RecordStorageLocation *getBaseObjectLocation(const MemberExpr , const Environment ); -/// Returns the fields of a `RecordDecl` that are initialized by an -/// `InitListExpr`, in the order in which they appear in -/// `InitListExpr::inits()`. -/// `Init->getType()` must be a record type. -std::vector -getFieldsForInitListExpr(const InitListExpr *InitList); - -/// Helper class for initialization of a record with an `InitListExpr`. -/// `InitListExpr::inits()` contains the initializers for both the base classes -/// and the fields of the record; this helper class separates these out into two -///