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,27 @@ return *cast(Vals.back().get()); } + // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, + // `getStableStorageLocation`, or something more appropriate. + + /// Creates a storage location appropriate for `Type`. Does not assign a value + /// to the returned storage location in the environment. + /// + /// Requirements: + /// + /// `Type` must not be null. + StorageLocation &createStorageLocation(QualType Type); + + /// Creates a storage location for `D`. Does not assign the returned storage + /// location to `D` in the environment. Does not assign a value to the + /// returned storage location in the environment. + StorageLocation &createStorageLocation(const VarDecl &D); + + /// Creates a storage location for `E`. Does not assign the returned storage + /// location to `E` in the environment. Does not assign a value to the + /// returned storage location in the environment. + StorageLocation &createStorageLocation(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,43 @@ namespace clang { namespace dataflow { +StorageLocation &DataflowAnalysisContext::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)); +} + +StorageLocation & +DataflowAnalysisContext::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 = getStorageLocation(D)) + return *Loc; + auto &Loc = createStorageLocation(D.getType()); + setStorageLocation(D, Loc); + return Loc; +} + +StorageLocation &DataflowAnalysisContext::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 = getStorageLocation(E)) + return *Loc; + auto &Loc = createStorageLocation(E.getType()); + setStorageLocation(E, Loc); + return Loc; +} + static std::pair makeCanonicalBoolValuePair(BoolValue &LHS, BoolValue &RHS) { auto Res = std::make_pair(&LHS, &RHS); @@ -175,3 +212,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,15 @@ } 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->createStorageLocation(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->createStorageLocation(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->createStorageLocation(E); } void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {