text: //===--- NameLookupImpl.h - Helpers used to implement lookup ----*- C++ -*-===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See https://swift.org/LICENSE.txt for license information
  // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  
  #ifndef SWIFT_AST_NAME_LOOKUP_IMPL_H
  #define SWIFT_AST_NAME_LOOKUP_IMPL_H
  
  #include "swift/AST/NameLookup.h"
  #include "swift/AST/ASTVisitor.h"
  #include "swift/AST/ParameterList.h"
  
  namespace swift {
  namespace namelookup {
  
  /// Performs a qualified lookup into the given module and, if necessary, its
  /// reexports, observing proper shadowing rules.
  void
  lookupVisibleDeclsInModule(ModuleDecl *M, ModuleDecl::AccessPathTy accessPath,
                             SmallVectorImpl<ValueDecl *> &decls,
                             NLKind lookupKind,
                             ResolutionKind resolutionKind,
                             LazyResolver *typeResolver,
                             const DeclContext *moduleScopeContext,
                             ArrayRef<ModuleDecl::ImportedModule> extraImports = {});
  
  /// Searches through statements and patterns for local variable declarations.
  class FindLocalVal : public StmtVisitor<FindLocalVal> {
    friend class ASTVisitor<FindLocalVal>;
  
    const SourceManager &SM;
    SourceLoc Loc;
    VisibleDeclConsumer &Consumer;
  
  public:
    FindLocalVal(const SourceManager &SM, SourceLoc Loc,
                 VisibleDeclConsumer &Consumer)
        : SM(SM), Loc(Loc), Consumer(Consumer) {}
  
    void checkValueDecl(ValueDecl *D, DeclVisibilityKind Reason) {
      Consumer.foundDecl(D, Reason);
    }
  
    void checkPattern(const Pattern *Pat, DeclVisibilityKind Reason) {
      switch (Pat->getKind()) {
      case PatternKind::Tuple:
        for (auto &field : cast<TuplePattern>(Pat)->getElements())
          checkPattern(field.getPattern(), Reason);
        return;
      case PatternKind::Paren:
      case PatternKind::Typed:
      case PatternKind::Var:
        return checkPattern(Pat->getSemanticsProvidingPattern(), Reason);
      case PatternKind::Named:
        return checkValueDecl(cast<NamedPattern>(Pat)->getDecl(), Reason);
      case PatternKind::EnumElement: {
        auto *OP = cast<EnumElementPattern>(Pat);
        if (OP->hasSubPattern())
          checkPattern(OP->getSubPattern(), Reason);
        return;
      }
      case PatternKind::OptionalSome:
        checkPattern(cast<OptionalSomePattern>(Pat)->getSubPattern(), Reason);
        return;
  
      case PatternKind::Is: {
        auto *isPat = cast<IsPattern>(Pat);
        if (isPat->hasSubPattern())
          checkPattern(isPat->getSubPattern(), Reason);
        return;
      }
  
      // Handle non-vars.
      case PatternKind::Bool:
      case PatternKind::Expr:
      case PatternKind::Any:
        return;
      }
    }
    
    void checkParameterList(const ParameterList *params) {
      for (auto param : *params) {
        checkValueDecl(param, DeclVisibilityKind::FunctionParameter);
      }
    }
  
    void checkGenericParams(GenericParamList *Params) {
      if (!Params)
        return;
  
      for (auto P : *Params)
        checkValueDecl(P, DeclVisibilityKind::GenericParameter);
    }
  
    void checkSourceFile(const SourceFile &SF) {
      for (Decl *D : SF.Decls)
        if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
          visitBraceStmt(TLCD->getBody(), /*isTopLevel=*/true);
    }
  
  private:
    bool isReferencePointInRange(SourceRange R) {
      return SM.rangeContainsTokenLoc(R, Loc);
    }
  
    void visitBreakStmt(BreakStmt *) {}
    void visitContinueStmt(ContinueStmt *) {}
    void visitFallthroughStmt(FallthroughStmt *) {}
    void visitFailStmt(FailStmt *) {}
    void visitReturnStmt(ReturnStmt *) {}
    void visitThrowStmt(ThrowStmt *) {}
    void visitDeferStmt(DeferStmt *DS) {
      // Nothing in the defer is visible.
    }
  
    void checkStmtCondition(const StmtCondition &Cond) {
      SourceLoc start = SourceLoc();
      for (auto entry : Cond) {
        if (start.isInvalid())
          start = entry.getStartLoc();
        if (auto *P = entry.getPatternOrNull()) {
          SourceRange previousConditionsToHere = SourceRange(start, entry.getEndLoc());
          if (!isReferencePointInRange(previousConditionsToHere))
            checkPattern(P, DeclVisibilityKind::LocalVariable);
        }
      }
    }
  
    void visitIfStmt(IfStmt *S) {
      if (!isReferencePointInRange(S->getSourceRange()))
        return;
  
      if (!S->getElseStmt() ||
          !isReferencePointInRange(S->getElseStmt()->getSourceRange())) {
        checkStmtCondition(S->getCond());
      }
  
      visit(S->getThenStmt());
      if (S->getElseStmt())
        visit(S->getElseStmt());
    }
    void visitGuardStmt(GuardStmt *S) {
      if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
        return;
  
      // Names in the guard aren't visible until after the body.
      if (!isReferencePointInRange(S->getBody()->getSourceRange()))
        checkStmtCondition(S->getCond());
  
      visit(S->getBody());
    }
  
    void visitWhileStmt(WhileStmt *S) {
      if (!isReferencePointInRange(S->getSourceRange()))
        return;
  
      checkStmtCondition(S->getCond());
      visit(S->getBody());
    }
    void visitRepeatWhileStmt(RepeatWhileStmt *S) {
      visit(S->getBody());
    }
    void visitDoStmt(DoStmt *S) {
      visit(S->getBody());
    }
  
    void visitForEachStmt(ForEachStmt *S) {
      if (!isReferencePointInRange(S->getSourceRange()))
        return;
      visit(S->getBody());
      if (!isReferencePointInRange(S->getSequence()->getSourceRange()))
        checkPattern(S->getPattern(), DeclVisibilityKind::LocalVariable);
    }
  
    void visitBraceStmt(BraceStmt *S, bool isTopLevelCode = false) {
      if (isTopLevelCode) {
        if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
          return;
      } else {
        if (!isReferencePointInRange(S->getSourceRange()))
          return;
      }
  
      for (auto elem : S->getElements()) {
        if (auto *S = elem.dyn_cast<Stmt*>())
          visit(S);
      }
      for (auto elem : S->getElements()) {
        if (auto *D = elem.dyn_cast<Decl*>()) {
          if (auto *VD = dyn_cast<ValueDecl>(D))
            checkValueDecl(VD, DeclVisibilityKind::LocalVariable);
        }
      }
    }
    
    void visitSwitchStmt(SwitchStmt *S) {
      if (!isReferencePointInRange(S->getSourceRange()))
        return;
      for (CaseStmt *C : S->getCases()) {
        visit(C);
      }
    }
  
    void visitCaseStmt(CaseStmt *S) {
      if (!isReferencePointInRange(S->getSourceRange()))
        return;
      // Pattern names aren't visible in the patterns themselves,
      // just in the body or in where guards.
      auto body = S->getBody();
      bool inPatterns = isReferencePointInRange(S->getLabelItemsRange());
      auto items = S->getCaseLabelItems();
      if (inPatterns) {
        for (const auto &CLI : items) {
          auto guard = CLI.getGuardExpr();
          if (guard && isReferencePointInRange(guard->getSourceRange())) {
            inPatterns = false;
            break;
          }
        }
      }
      if (!inPatterns && !items.empty())
        checkPattern(items[0].getPattern(), DeclVisibilityKind::LocalVariable);
      visit(body);
    }
  
    void visitDoCatchStmt(DoCatchStmt *S) {
      if (!isReferencePointInRange(S->getSourceRange()))
        return;
      visit(S->getBody());
      visitCatchClauses(S->getCatches());
    }
    void visitCatchClauses(ArrayRef<CatchStmt*> clauses) {
      // TODO: some sort of binary search?
      for (auto clause : clauses) {
        visitCatchStmt(clause);
      }
    }
    void visitCatchStmt(CatchStmt *S) {
      if (!isReferencePointInRange(S->getSourceRange()))
        return;
      // Names in the pattern aren't visible until after the pattern.
      if (!isReferencePointInRange(S->getErrorPattern()->getSourceRange()))
        checkPattern(S->getErrorPattern(), DeclVisibilityKind::LocalVariable);
      visit(S->getBody());
    }
    
  };
  
  } // end namespace namelookup
  } // end namespace swift
  
  #endif
  