<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  <NAME> <<EMAIL>>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/LookupHelper.h"

#include "DeclUnloader.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"

using namespace clang;

namespace clang {

  ///\brief Cleanup Parser state after a failed lookup.
  ///
  /// After a failed lookup we need to discard the remaining unparsed input,
  /// restore the original state of the incremental parsing flag, clear any
  /// pending diagnostics, restore the suppress diagnostics flag, and restore
  /// the spell checking language options.
  ///
  class ParserStateRAII {
  private:
    Parser* P;
    Preprocessor& PP;
    decltype(Parser::TemplateIds) OldTemplateIds;
    bool ResetIncrementalProcessing;
    bool OldSuppressAllDiagnostics;
    bool OldPPSuppressAllDiagnostics;
    bool OldSpellChecking;
    SourceLocation OldPrevTokLocation;
    unsigned short OldParenCount, OldBracketCount, OldBraceCount;
    unsigned OldTemplateParameterDepth;
    bool OldInNonInstantiationSFINAEContext;

  public:
    ParserStateRAII(Parser& p)
      : P(&p), PP(p.getPreprocessor()),
        ResetIncrementalProcessing(p.getPreprocessor()
                                   .isIncrementalProcessingEnabled()),
        OldSuppressAllDiagnostics(P->getActions().getDiagnostics()
                                  .getSuppressAllDiagnostics()),
        OldPPSuppressAllDiagnostics(p.getPreprocessor().getDiagnostics()
                                  .getSuppressAllDiagnostics()),
        OldSpellChecking(p.getPreprocessor().getLangOpts().SpellChecking),
        OldPrevTokLocation(p.PrevTokLocation),
        OldParenCount(p.ParenCount), OldBracketCount(p.BracketCount),
        OldBraceCount(p.BraceCount),
        OldTemplateParameterDepth(p.TemplateParameterDepth),
        OldInNonInstantiationSFINAEContext(P->getActions()
                                           .InNonInstantiationSFINAEContext)
    {
       OldTemplateIds.swap(P->TemplateIds);
    }

    ~ParserStateRAII()
    {
      //
      // Advance the parser to the end of the file, and pop the include stack.
      //
      // Note: Consuming the EOF token will pop the include stack.
      //
      {
         // Cleanup the TemplateIds before swapping the previous set back.
         DestroyTemplateIdAnnotationsRAIIObj CleanupTemplateIds(*P);
      }
      P->TemplateIds.swap(OldTemplateIds);
      P->SkipUntil(tok::eof);
      PP.enableIncrementalProcessing(ResetIncrementalProcessing);
      // Doesn't reset the diagnostic mappings
      P->getActions().getDiagnostics().Reset(/*soft=*/true);
      P->getActions().getDiagnostics().setSuppressAllDiagnostics(OldSuppressAllDiagnostics);
      PP.getDiagnostics().Reset(/*soft=*/true);
      PP.getDiagnostics().setSuppressAllDiagnostics(OldPPSuppressAllDiagnostics);
      const_cast<LangOptions&>(PP.getLangOpts()).SpellChecking =
         OldSpellChecking;

      P->PrevTokLocation = OldPrevTokLocation;
      P->ParenCount = OldParenCount;
      P->BracketCount = OldBracketCount;
      P->BraceCount = OldBraceCount;
      P->TemplateParameterDepth = OldTemplateParameterDepth;
      P->getActions().InNonInstantiationSFINAEContext =
         OldInNonInstantiationSFINAEContext;
    }
  };
}

namespace cling {
  ///\brief Class to help with the custom allocation of clang::Expr
  ///
  struct ExprAlloc {
     char fBuffer[sizeof(clang::OpaqueValueExpr)];
  };

  // pin *tor here so that we can have clang::Parser defined and be able to call
  // the dtor on the OwningPtr
  LookupHelper::LookupHelper(clang::Parser* P, Interpreter* interp)
    : m_Parser(P), m_Interpreter(interp) {}

  LookupHelper::~LookupHelper() {}

  static
  DeclContext* getCompleteContext(const Decl* scopeDecl,
                                  ASTContext& Context, Sema &S);

  static void prepareForParsing(Parser& P,
                                const Interpreter* Interp,
                                llvm::StringRef code,
                                llvm::StringRef bufferName,
                                LookupHelper::DiagSetting diagOnOff) {
    //Parser& P = *m_Parser;
    Sema& S = P.getActions();
    Preprocessor& PP = P.getPreprocessor();
    //
    //  Tell the diagnostic engine to ignore all diagnostics.
    //
    P.getActions().getDiagnostics().setSuppressAllDiagnostics(
                                      diagOnOff == LookupHelper::NoDiagnostics);
    PP.getDiagnostics().setSuppressAllDiagnostics(
                                      diagOnOff == LookupHelper::NoDiagnostics);
    //
    //  Tell Sema we are not in the process of doing an instantiation.
    //
    P.getActions().InNonInstantiationSFINAEContext = true;
    //
    //  Tell the parser to not attempt spelling correction.
    //
    const_cast<LangOptions&>(PP.getLangOpts()).SpellChecking = 0;
    //
    //  Turn on ignoring of the main file eof token.
    //
    //  Note: We need this because token readahead in the following
    //        routine calls ends up parsing it multiple times.
    //
    if (!PP.isIncrementalProcessingEnabled()) {
      PP.enableIncrementalProcessing();
    }
    assert(!code.empty()&&"prepareForParsing should only be called when needd");

    //
    //  Create a fake file to parse the type name.
    //
    std::unique_ptr<llvm::MemoryBuffer>
      SB = llvm::MemoryBuffer::getMemBufferCopy(code.str() + "\n",
                                                bufferName.str());
    SourceLocation NewLoc = Interp->getNextAvailableLoc();
    FileID FID = S.getSourceManager().createFileID(std::move(SB),
                                                   SrcMgr::C_User,
                                                   /*LoadedID*/0,
                                                   /*LoadedOffset*/0, NewLoc);
    //
    //  Switch to the new file the way #include does.
    //
    //  Note: To switch back to the main file we must consume an eof token.
    //
    PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc);
    PP.Lex(const_cast<Token&>(P.getCurToken()));
  }

  static const TagDecl* RequireCompleteDeclContext(Sema& S,
                                                   Preprocessor& PP,
                                                   const TagDecl *tobeCompleted,
                                                   LookupHelper::DiagSetting diagOnOff)
  {
    // getContextAndSpec create the CXXScopeSpec and requires the scope
    // to be complete, so this is exactly what we need.

    bool OldSuppressAllDiagnostics(PP.getDiagnostics()
                                   .getSuppressAllDiagnostics());
    PP.getDiagnostics().setSuppressAllDiagnostics(
                                      diagOnOff == LookupHelper::NoDiagnostics);

    ASTContext& Context = S.getASTContext();
    DeclContext* complete = getCompleteContext(tobeCompleted,Context,S);

    PP.getDiagnostics().setSuppressAllDiagnostics(OldSuppressAllDiagnostics);

    if (complete) {
      const TagDecl *result = dyn_cast<TagDecl>(complete);
      return result->getDefinition();
    } else return 0;
  }

  ///\brief Look for a tag decl based on its name
  ///
  ///\param declName name of the class, enum, uniorn or namespace being
  ///       looked for
  ///\param resultDecl pointer that will be updated with the answer
  ///\param P Parse to use for the search
  ///\param diagOnOff whether the error diagnostics are printed or not.
  ///\return returns true if the answer is authoritative or false if a more<commit_msg>Fix Coverity CID61311 - potential null deref.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  <NAME> <<EMAIL>>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "cling/Interpreter/LookupHelper.h"

#include "DeclUnloader.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Utils/AST.h"

#include "clang/AST/ASTContext.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"

using namespace clang;

namespace clang {

  ///\brief Cleanup Parser state after a failed lookup.
  ///
  /// After a failed lookup we need to discard the remaining unparsed input,
  /// restore the original state of the incremental parsing flag, clear any
  /// pending diagnostics, restore the suppress diagnostics flag, and restore
  /// the spell checking language options.
  ///
  class ParserStateRAII {
  private:
    Parser* P;
    Preprocessor& PP;
    decltype(Parser::TemplateIds) OldTemplateIds;
    bool ResetIncrementalProcessing;
    bool OldSuppressAllDiagnostics;
    bool OldPPSuppressAllDiagnostics;
    bool OldSpellChecking;
    SourceLocation OldPrevTokLocation;
    unsigned short OldParenCount, OldBracketCount, OldBraceCount;
    unsigned OldTemplateParameterDepth;
    bool OldInNonInstantiationSFINAEContext;

  public:
    ParserStateRAII(Parser& p)
      : P(&p), PP(p.getPreprocessor()),
        ResetIncrementalProcessing(p.getPreprocessor()
                                   .isIncrementalProcessingEnabled()),
        OldSuppressAllDiagnostics(P->getActions().getDiagnostics()
                                  .getSuppressAllDiagnostics()),
        OldPPSuppressAllDiagnostics(p.getPreprocessor().getDiagnostics()
                                  .getSuppressAllDiagnostics()),
        OldSpellChecking(p.getPreprocessor().getLangOpts().SpellChecking),
        OldPrevTokLocation(p.PrevTokLocation),
        OldParenCount(p.ParenCount), OldBracketCount(p.BracketCount),
        OldBraceCount(p.BraceCount),
        OldTemplateParameterDepth(p.TemplateParameterDepth),
        OldInNonInstantiationSFINAEContext(P->getActions()
                                           .InNonInstantiationSFINAEContext)
    {
       OldTemplateIds.swap(P->TemplateIds);
    }

    ~ParserStateRAII()
    {
      //
      // Advance the parser to the end of the file, and pop the include stack.
      //
      // Note: Consuming the EOF token will pop the include stack.
      //
      {
         // Cleanup the TemplateIds before swapping the previous set back.
         DestroyTemplateIdAnnotationsRAIIObj CleanupTemplateIds(*P);
      }
      P->TemplateIds.swap(OldTemplateIds);
      P->SkipUntil(tok::eof);
      PP.enableIncrementalProcessing(ResetIncrementalProcessing);
      // Doesn't reset the diagnostic mappings
      P->getActions().getDiagnostics().Reset(/*soft=*/true);
      P->getActions().getDiagnostics().setSuppressAllDiagnostics(OldSuppressAllDiagnostics);
      PP.getDiagnostics().Reset(/*soft=*/true);
      PP.getDiagnostics().setSuppressAllDiagnostics(OldPPSuppressAllDiagnostics);
      const_cast<LangOptions&>(PP.getLangOpts()).SpellChecking =
         OldSpellChecking;

      P->PrevTokLocation = OldPrevTokLocation;
      P->ParenCount = OldParenCount;
      P->BracketCount = OldBracketCount;
      P->BraceCount = OldBraceCount;
      P->TemplateParameterDepth = OldTemplateParameterDepth;
      P->getActions().InNonInstantiationSFINAEContext =
         OldInNonInstantiationSFINAEContext;
    }
  };
}

namespace cling {
  ///\brief Class to help with the custom allocation of clang::Expr
  ///
  struct ExprAlloc {
     char fBuffer[sizeof(clang::OpaqueValueExpr)];
  };

  // pin *tor here so that we can have clang::Parser defined and be able to call
  // the dtor on the OwningPtr
  LookupHelper::LookupHelper(clang::Parser* P, Interpreter* interp)
    : m_Parser(P), m_Interpreter(interp) {}

  LookupHelper::~LookupHelper() {}

  static
  DeclContext* getCompleteContext(const Decl* scopeDecl,
                                  ASTContext& Context, Sema &S);

  static void prepareForParsing(Parser& P,
                                const Interpreter* Interp,
                                llvm::StringRef code,
                                llvm::StringRef bufferName,
                                LookupHelper::DiagSetting diagOnOff) {
    //Parser& P = *m_Parser;
    Sema& S = P.getActions();
    Preprocessor& PP = P.getPreprocessor();
    //
    //  Tell the diagnostic engine to ignore all diagnostics.
    //
    P.getActions().getDiagnostics().setSuppressAllDiagnostics(
                                      diagOnOff == LookupHelper::NoDiagnostics);
    PP.getDiagnostics().setSuppressAllDiagnostics(
                                      diagOnOff == LookupHelper::NoDiagnostics);
    //
    //  Tell Sema we are not in the process of doing an instantiation.
    //
    P.getActions().InNonInstantiationSFINAEContext = true;
    //
    //  Tell the parser to not attempt spelling correction.
    //
    const_cast<LangOptions&>(PP.getLangOpts()).SpellChecking = 0;
    //
    //  Turn on ignoring of the main file eof token.
    //
    //  Note: We need this because token readahead in the following
    //        routine calls ends up parsing it multiple times.
    //
    if (!PP.isIncrementalProcessingEnabled()) {
      PP.enableIncrementalProcessing();
    }
    assert(!code.empty()&&"prepareForParsing should only be called when needd");

    //
    //  Create a fake file to parse the type name.
    //
    std::unique_ptr<llvm::MemoryBuffer>
      SB = llvm::MemoryBuffer::getMemBufferCopy(code.str() + "\n",
                                                bufferName.str());
    SourceLocation NewLoc = Interp->getNextAvailableLoc();
    FileID FID = S.getSourceManager().createFileID(std::move(SB),
                                                   SrcMgr::C_User,
                                                   /*LoadedID*/0,
                                                   /*LoadedOffset*/0, NewLoc);
    //
    //  Switch to the new file the way #include does.
    //
    //  Note: To switch back to the main file we must consume an eof token.
    //
    PP.EnterSourceFile(FID, /*DirLookup*/0, NewLoc);
    PP.Lex(const_cast<Token&>(P.getCurToken()));
  }

  static const TagDecl* RequireCompleteDeclContext(Sema& S,
                                                   Preprocessor& PP,
                                                   const TagDecl *tobeCompleted,
                                                   LookupHelper::DiagSetting diagOnOff)
  {
    // getContextAndSpec create the CXXScopeSpec and requires the scope
    // to be complete, so this is exactly what we need.

    bool OldSuppressAllDiagnostics(PP.getDiagnostics()
                                   .getSuppressAllDiagnostics());
    PP.getDiagnostics().setSuppressAllDiagnostics(
                                      diagOnOff == LookupHelper::NoDiagnostics);

    ASTContext& Context = S.getASTContext();
    DeclContext* complete = getCompleteContext(tobeCompleted,Context,S);

    PP.getDiagnostics().setSuppressAllDiagnostics(OldSuppressAllDiagnostics);

    if (!complete)
      return 0;
    if (const TagDecl *result = dyn_cast<TagDecl>(complete))
      return result->getDefinition();
    return 0;
  }

  ///\brief Look for a tag decl based on its name
  ///
  ///\param declName name of the class, enum, uniorn or namespace being
  ///       looked for
  ///\param resultDecl pointer that will be updated with the answer
  ///\param P Parse to use for the search
  ///\param diagOnOff whether the error diagnostics are printed or not.
  ///\return returns true if the answer is authoritative or false if a more
{'fraction_non_alphanumeric': 0.11603044213578159, 'fraction_numerical': 0.0009664170089393573, 'mean_word_length': 2.2344207853096307, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 48, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7535594', 'n_tokens_mistral': 4420, 'n_tokens_neox': 4421, 'n_words': 1094}