//===- ODRDiagsEmitter.h - Emits diagnostic for ODR mismatches --*- 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
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_AST_ODRDIAGSEMITTER_H
 
#define LLVM_CLANG_AST_ODRDIAGSEMITTER_H
 
 
 
#include "clang/AST/ASTContext.h"
 
#include "clang/AST/DeclCXX.h"
 
#include "clang/AST/DeclObjC.h"
 
#include "clang/Basic/Diagnostic.h"
 
#include "clang/Basic/LangOptions.h"
 
 
 
namespace clang {
 
 
 
class ODRDiagsEmitter {
 
public:
 
  ODRDiagsEmitter(DiagnosticsEngine &Diags, const ASTContext &Context,
 
                  const LangOptions &LangOpts)
 
      : Diags(Diags), Context(Context), LangOpts(LangOpts) {}
 
 
 
  /// Diagnose ODR mismatch between 2 FunctionDecl.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  bool diagnoseMismatch(const FunctionDecl *FirstFunction,
 
                        const FunctionDecl *SecondFunction) const;
 
 
 
  /// Diagnose ODR mismatch between 2 EnumDecl.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  bool diagnoseMismatch(const EnumDecl *FirstEnum,
 
                        const EnumDecl *SecondEnum) const;
 
 
 
  /// Diagnose ODR mismatch between 2 CXXRecordDecl.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  /// To compare 2 declarations with merged and identical definition data
 
  /// you need to provide pre-merge definition data in \p SecondDD.
 
  bool
 
  diagnoseMismatch(const CXXRecordDecl *FirstRecord,
 
                   const CXXRecordDecl *SecondRecord,
 
                   const struct CXXRecordDecl::DefinitionData *SecondDD) const;
 
 
 
  /// Diagnose ODR mismatch between 2 RecordDecl that are not CXXRecordDecl.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  bool diagnoseMismatch(const RecordDecl *FirstRecord,
 
                        const RecordDecl *SecondRecord) const;
 
 
 
  /// Diagnose ODR mismatch between 2 ObjCInterfaceDecl.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  bool diagnoseMismatch(
 
      const ObjCInterfaceDecl *FirstID, const ObjCInterfaceDecl *SecondID,
 
      const struct ObjCInterfaceDecl::DefinitionData *SecondDD) const;
 
 
 
  /// Diagnose ODR mismatch between ObjCInterfaceDecl with different
 
  /// definitions.
 
  bool diagnoseMismatch(const ObjCInterfaceDecl *FirstID,
 
                        const ObjCInterfaceDecl *SecondID) const {
 
    assert(FirstID->data().Definition != SecondID->data().Definition &&
 
           "Don't diagnose differences when definitions are merged already");
 
    return diagnoseMismatch(FirstID, SecondID, &SecondID->data());
 
  }
 
 
 
  /// Diagnose ODR mismatch between 2 ObjCProtocolDecl.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  /// To compare 2 declarations with merged and identical definition data
 
  /// you need to provide pre-merge definition data in \p SecondDD.
 
  bool diagnoseMismatch(
 
      const ObjCProtocolDecl *FirstProtocol,
 
      const ObjCProtocolDecl *SecondProtocol,
 
      const struct ObjCProtocolDecl::DefinitionData *SecondDD) const;
 
 
 
  /// Diagnose ODR mismatch between ObjCProtocolDecl with different definitions.
 
  bool diagnoseMismatch(const ObjCProtocolDecl *FirstProtocol,
 
                        const ObjCProtocolDecl *SecondProtocol) const {
 
    assert(FirstProtocol->data().Definition !=
 
               SecondProtocol->data().Definition &&
 
           "Don't diagnose differences when definitions are merged already");
 
    return diagnoseMismatch(FirstProtocol, SecondProtocol,
 
                            &SecondProtocol->data());
 
  }
 
 
 
  /// Get the best name we know for the module that owns the given
 
  /// declaration, or an empty string if the declaration is not from a module.
 
  static std::string getOwningModuleNameForDiagnostic(const Decl *D);
 
 
 
private:
 
  using DeclHashes = llvm::SmallVector<std::pair<const Decl *, unsigned>, 4>;
 
 
 
  // Used with err_module_odr_violation_mismatch_decl,
 
  // note_module_odr_violation_mismatch_decl,
 
  // err_module_odr_violation_mismatch_decl_unknown,
 
  // and note_module_odr_violation_mismatch_decl_unknown
 
  // This list should be the same Decl's as in ODRHash::isSubDeclToBeProcessed
 
  enum ODRMismatchDecl {
 
    EndOfClass,
 
    PublicSpecifer,
 
    PrivateSpecifer,
 
    ProtectedSpecifer,
 
    StaticAssert,
 
    Field,
 
    CXXMethod,
 
    TypeAlias,
 
    TypeDef,
 
    Var,
 
    Friend,
 
    FunctionTemplate,
 
    ObjCMethod,
 
    ObjCIvar,
 
    ObjCProperty,
 
    Other
 
  };
 
 
 
  struct DiffResult {
 
    const Decl *FirstDecl = nullptr, *SecondDecl = nullptr;
 
    ODRMismatchDecl FirstDiffType = Other, SecondDiffType = Other;
 
  };
 
 
 
  // If there is a diagnoseable difference, FirstDiffType and
 
  // SecondDiffType will not be Other and FirstDecl and SecondDecl will be
 
  // filled in if not EndOfClass.
 
  static DiffResult FindTypeDiffs(DeclHashes &FirstHashes,
 
                                  DeclHashes &SecondHashes);
 
 
 
  DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const {
 
    return Diags.Report(Loc, DiagID);
 
  }
 
 
 
  // Use this to diagnose that an unexpected Decl was encountered
 
  // or no difference was detected. This causes a generic error
 
  // message to be emitted.
 
  void diagnoseSubMismatchUnexpected(DiffResult &DR,
 
                                     const NamedDecl *FirstRecord,
 
                                     StringRef FirstModule,
 
                                     const NamedDecl *SecondRecord,
 
                                     StringRef SecondModule) const;
 
 
 
  void diagnoseSubMismatchDifferentDeclKinds(DiffResult &DR,
 
                                             const NamedDecl *FirstRecord,
 
                                             StringRef FirstModule,
 
                                             const NamedDecl *SecondRecord,
 
                                             StringRef SecondModule) const;
 
 
 
  bool diagnoseSubMismatchField(const NamedDecl *FirstRecord,
 
                                StringRef FirstModule, StringRef SecondModule,
 
                                const FieldDecl *FirstField,
 
                                const FieldDecl *SecondField) const;
 
 
 
  bool diagnoseSubMismatchTypedef(const NamedDecl *FirstRecord,
 
                                  StringRef FirstModule, StringRef SecondModule,
 
                                  const TypedefNameDecl *FirstTD,
 
                                  const TypedefNameDecl *SecondTD,
 
                                  bool IsTypeAlias) const;
 
 
 
  bool diagnoseSubMismatchVar(const NamedDecl *FirstRecord,
 
                              StringRef FirstModule, StringRef SecondModule,
 
                              const VarDecl *FirstVD,
 
                              const VarDecl *SecondVD) const;
 
 
 
  /// Check if protocol lists are the same and diagnose if they are different.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  bool diagnoseSubMismatchProtocols(const ObjCProtocolList &FirstProtocols,
 
                                    const ObjCContainerDecl *FirstContainer,
 
                                    StringRef FirstModule,
 
                                    const ObjCProtocolList &SecondProtocols,
 
                                    const ObjCContainerDecl *SecondContainer,
 
                                    StringRef SecondModule) const;
 
 
 
  /// Check if Objective-C methods are the same and diagnose if different.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  bool diagnoseSubMismatchObjCMethod(const NamedDecl *FirstObjCContainer,
 
                                     StringRef FirstModule,
 
                                     StringRef SecondModule,
 
                                     const ObjCMethodDecl *FirstMethod,
 
                                     const ObjCMethodDecl *SecondMethod) const;
 
 
 
  /// Check if Objective-C properties are the same and diagnose if different.
 
  ///
 
  /// Returns true if found a mismatch and diagnosed it.
 
  bool
 
  diagnoseSubMismatchObjCProperty(const NamedDecl *FirstObjCContainer,
 
                                  StringRef FirstModule, StringRef SecondModule,
 
                                  const ObjCPropertyDecl *FirstProp,
 
                                  const ObjCPropertyDecl *SecondProp) const;
 
 
 
private:
 
  DiagnosticsEngine &Diags;
 
  const ASTContext &Context;
 
  const LangOptions &LangOpts;
 
};
 
 
 
} // namespace clang
 
 
 
#endif