| //===-- Value.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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines classes for values computed by abstract interpretation |
| // during dataflow analysis. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_VALUE_H |
| #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_VALUE_H |
| |
| #include "clang/AST/Decl.h" |
| #include "clang/Analysis/FlowSensitive/StorageLocation.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include <cassert> |
| #include <utility> |
| |
| namespace clang { |
| namespace dataflow { |
| |
| /// Base class for all values computed by abstract interpretation. |
| class Value { |
| public: |
| enum class Kind { |
| Integer, |
| Reference, |
| Pointer, |
| Struct, |
| |
| // Synthetic boolean values are either atomic values or composites that |
| // represent conjunctions, disjunctions, and negations. |
| AtomicBool, |
| Conjunction, |
| Disjunction, |
| Negation |
| }; |
| |
| explicit Value(Kind ValKind) : ValKind(ValKind) {} |
| |
| virtual ~Value() = default; |
| |
| Kind getKind() const { return ValKind; } |
| |
| private: |
| Kind ValKind; |
| }; |
| |
| /// Models a boolean. |
| class BoolValue : public Value { |
| public: |
| explicit BoolValue(Kind ValueKind) : Value(ValueKind) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::AtomicBool || |
| Val->getKind() == Kind::Conjunction || |
| Val->getKind() == Kind::Disjunction || |
| Val->getKind() == Kind::Negation; |
| } |
| }; |
| |
| /// Models an atomic boolean. |
| class AtomicBoolValue : public BoolValue { |
| public: |
| explicit AtomicBoolValue() : BoolValue(Kind::AtomicBool) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::AtomicBool; |
| } |
| }; |
| |
| /// Models a boolean conjunction. |
| // FIXME: Consider representing binary and unary boolean operations similar |
| // to how they are represented in the AST. This might become more pressing |
| // when such operations need to be added for other data types. |
| class ConjunctionValue : public BoolValue { |
| public: |
| explicit ConjunctionValue(BoolValue &LeftSubVal, BoolValue &RightSubVal) |
| : BoolValue(Kind::Conjunction), LeftSubVal(LeftSubVal), |
| RightSubVal(RightSubVal) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Conjunction; |
| } |
| |
| /// Returns the left sub-value of the conjunction. |
| BoolValue &getLeftSubValue() const { return LeftSubVal; } |
| |
| /// Returns the right sub-value of the conjunction. |
| BoolValue &getRightSubValue() const { return RightSubVal; } |
| |
| private: |
| BoolValue &LeftSubVal; |
| BoolValue &RightSubVal; |
| }; |
| |
| /// Models a boolean disjunction. |
| class DisjunctionValue : public BoolValue { |
| public: |
| explicit DisjunctionValue(BoolValue &LeftSubVal, BoolValue &RightSubVal) |
| : BoolValue(Kind::Disjunction), LeftSubVal(LeftSubVal), |
| RightSubVal(RightSubVal) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Disjunction; |
| } |
| |
| /// Returns the left sub-value of the disjunction. |
| BoolValue &getLeftSubValue() const { return LeftSubVal; } |
| |
| /// Returns the right sub-value of the disjunction. |
| BoolValue &getRightSubValue() const { return RightSubVal; } |
| |
| private: |
| BoolValue &LeftSubVal; |
| BoolValue &RightSubVal; |
| }; |
| |
| /// Models a boolean negation. |
| class NegationValue : public BoolValue { |
| public: |
| explicit NegationValue(BoolValue &SubVal) |
| : BoolValue(Kind::Negation), SubVal(SubVal) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Negation; |
| } |
| |
| /// Returns the sub-value of the negation. |
| BoolValue &getSubVal() const { return SubVal; } |
| |
| private: |
| BoolValue &SubVal; |
| }; |
| |
| /// Models an integer. |
| class IntegerValue : public Value { |
| public: |
| explicit IntegerValue() : Value(Kind::Integer) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Integer; |
| } |
| }; |
| |
| /// Base class for values that refer to storage locations. |
| class IndirectionValue : public Value { |
| public: |
| /// Constructs a value that refers to `PointeeLoc`. |
| explicit IndirectionValue(Kind ValueKind, StorageLocation &PointeeLoc) |
| : Value(ValueKind), PointeeLoc(PointeeLoc) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Reference || Val->getKind() == Kind::Pointer; |
| } |
| |
| StorageLocation &getPointeeLoc() const { return PointeeLoc; } |
| |
| private: |
| StorageLocation &PointeeLoc; |
| }; |
| |
| /// Models a dereferenced pointer. For example, a reference in C++ or an lvalue |
| /// in C. |
| class ReferenceValue final : public IndirectionValue { |
| public: |
| explicit ReferenceValue(StorageLocation &PointeeLoc) |
| : IndirectionValue(Kind::Reference, PointeeLoc) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Reference; |
| } |
| }; |
| |
| /// Models a symbolic pointer. Specifically, any value of type `T*`. |
| class PointerValue final : public IndirectionValue { |
| public: |
| explicit PointerValue(StorageLocation &PointeeLoc) |
| : IndirectionValue(Kind::Pointer, PointeeLoc) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Pointer; |
| } |
| }; |
| |
| /// Models a value of `struct` or `class` type, with a flat map of fields to |
| /// child storage locations, containing all accessible members of base struct |
| /// and class types. |
| class StructValue final : public Value { |
| public: |
| StructValue() : StructValue(llvm::DenseMap<const ValueDecl *, Value *>()) {} |
| |
| explicit StructValue(llvm::DenseMap<const ValueDecl *, Value *> Children) |
| : Value(Kind::Struct), Children(std::move(Children)) {} |
| |
| static bool classof(const Value *Val) { |
| return Val->getKind() == Kind::Struct; |
| } |
| |
| /// Returns the child value that is assigned for `D` or null if the child is |
| /// not initialized. |
| Value *getChild(const ValueDecl &D) const { |
| auto It = Children.find(&D); |
| if (It == Children.end()) |
| return nullptr; |
| return It->second; |
| } |
| |
| /// Assigns `Val` as the child value for `D`. |
| void setChild(const ValueDecl &D, Value &Val) { Children[&D] = &Val; } |
| |
| /// Returns the value of the synthetic property with the given `Name` or null |
| /// if the property isn't assigned a value. |
| Value *getProperty(llvm::StringRef Name) const { |
| auto It = Properties.find(Name); |
| return It == Properties.end() ? nullptr : It->second; |
| } |
| |
| /// Assigns `Val` as the value of the synthetic property with the given |
| /// `Name`. |
| void setProperty(llvm::StringRef Name, Value &Val) { |
| Properties.insert_or_assign(Name, &Val); |
| } |
| |
| private: |
| llvm::DenseMap<const ValueDecl *, Value *> Children; |
| llvm::StringMap<Value *> Properties; |
| }; |
| |
| } // namespace dataflow |
| } // namespace clang |
| |
| #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_VALUE_H |