diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -44,6 +44,9 @@ const Expr &ignoreCFGOmittedNodes(const Expr &E); const Stmt &ignoreCFGOmittedNodes(const Stmt &S); +/// Gets the set of all fields in the type. +llvm::DenseSet getObjectFields(QualType Type); + /// Owns objects that encompass the state of a program and stores context that /// is used during dataflow analysis. class DataflowAnalysisContext { @@ -85,6 +88,19 @@ return *cast(Vals.back().get()); } + /// Returns a stable storage location appropriate for `Type`. + /// + /// Requirements: + /// + /// `Type` must not be null. + StorageLocation &getStableStorageLocation(QualType Type); + + /// Returns a stable storage location for `D`. + StorageLocation &getStableStorageLocation(const VarDecl &D); + + /// Returns a stable storage location for `E`. + StorageLocation &getStableStorageLocation(const Expr &E); + /// Assigns `Loc` as the storage location of `D`. /// /// Requirements: diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -22,6 +22,39 @@ namespace clang { namespace dataflow { +StorageLocation & +DataflowAnalysisContext::getStableStorageLocation(QualType Type) { + assert(!Type.isNull()); + if (Type->isStructureOrClassType() || Type->isUnionType()) { + // FIXME: Explore options to avoid eager initialization of fields as some of + // them might not be needed for a particular analysis. + llvm::DenseMap FieldLocs; + for (const FieldDecl *Field : getObjectFields(Type)) + FieldLocs.insert({Field, &getStableStorageLocation(Field->getType())}); + return takeOwnership( + std::make_unique(Type, std::move(FieldLocs))); + } + return takeOwnership(std::make_unique(Type)); +} + +StorageLocation & +DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) { + if (auto *Loc = getStorageLocation(D)) + return *Loc; + auto &Loc = getStableStorageLocation(D.getType()); + setStorageLocation(D, Loc); + return Loc; +} + +StorageLocation & +DataflowAnalysisContext::getStableStorageLocation(const Expr &E) { + if (auto *Loc = getStorageLocation(E)) + return *Loc; + auto &Loc = getStableStorageLocation(E.getType()); + setStorageLocation(E, Loc); + return Loc; +} + static std::pair makeCanonicalBoolValuePair(BoolValue &LHS, BoolValue &RHS) { auto Res = std::make_pair(&LHS, &RHS); @@ -175,3 +208,27 @@ return ignoreCFGOmittedNodes(*E); return S; } + +// FIXME: Does not precisely handle non-virtual diamond inheritance. A single +// field decl will be modeled for all instances of the inherited field. +static void +getFieldsFromClassHierarchy(QualType Type, + llvm::DenseSet &Fields) { + if (Type->isIncompleteType() || Type->isDependentType() || + !Type->isRecordType()) + return; + + for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) + Fields.insert(Field); + if (auto *CXXRecord = Type->getAsCXXRecordDecl()) + for (const CXXBaseSpecifier &Base : CXXRecord->bases()) + getFieldsFromClassHierarchy(Base.getType(), Fields); +} + +/// Gets the set of all fields in the type. +llvm::DenseSet +clang::dataflow::getObjectFields(QualType Type) { + llvm::DenseSet Fields; + getFieldsFromClassHierarchy(Type, Fields); + return Fields; +} diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -152,29 +152,6 @@ } } -// FIXME: Does not precisely handle non-virtual diamond inheritance. A single -// field decl will be modeled for all instances of the inherited field. -static void -getFieldsFromClassHierarchy(QualType Type, - llvm::DenseSet &Fields) { - if (Type->isIncompleteType() || Type->isDependentType() || - !Type->isRecordType()) - return; - - for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) - Fields.insert(Field); - if (auto *CXXRecord = Type->getAsCXXRecordDecl()) - for (const CXXBaseSpecifier &Base : CXXRecord->bases()) - getFieldsFromClassHierarchy(Base.getType(), Fields); -} - -/// Gets the set of all fields in the type. -static llvm::DenseSet getObjectFields(QualType Type) { - llvm::DenseSet Fields; - getFieldsFromClassHierarchy(Type, Fields); - return Fields; -} - Environment::Environment(DataflowAnalysisContext &DACtx) : DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {} @@ -310,39 +287,21 @@ } StorageLocation &Environment::createStorageLocation(QualType Type) { - assert(!Type.isNull()); - if (Type->isStructureOrClassType() || Type->isUnionType()) { - // FIXME: Explore options to avoid eager initialization of fields as some of - // them might not be needed for a particular analysis. - llvm::DenseMap FieldLocs; - for (const FieldDecl *Field : getObjectFields(Type)) - FieldLocs.insert({Field, &createStorageLocation(Field->getType())}); - return takeOwnership( - std::make_unique(Type, std::move(FieldLocs))); - } - return takeOwnership(std::make_unique(Type)); + return DACtx->getStableStorageLocation(Type); } StorageLocation &Environment::createStorageLocation(const VarDecl &D) { // Evaluated declarations are always assigned the same storage locations to // ensure that the environment stabilizes across loop iterations. Storage // locations for evaluated declarations are stored in the analysis context. - if (auto *Loc = DACtx->getStorageLocation(D)) - return *Loc; - auto &Loc = createStorageLocation(D.getType()); - DACtx->setStorageLocation(D, Loc); - return Loc; + return DACtx->getStableStorageLocation(D); } StorageLocation &Environment::createStorageLocation(const Expr &E) { // Evaluated expressions are always assigned the same storage locations to // ensure that the environment stabilizes across loop iterations. Storage // locations for evaluated expressions are stored in the analysis context. - if (auto *Loc = DACtx->getStorageLocation(E)) - return *Loc; - auto &Loc = createStorageLocation(E.getType()); - DACtx->setStorageLocation(E, Loc); - return Loc; + return DACtx->getStableStorageLocation(E); } void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {