예제 #1
0
파일: Parser.cpp 프로젝트: randomstep/swift
Parser::Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
               SILParserTUStateBase *SIL,
               PersistentParserState *PersistentState)
  : SourceMgr(SF.getASTContext().SourceMgr),
    Diags(SF.getASTContext().Diags),
    SF(SF),
    L(Lex.release()),
    SIL(SIL),
    CurDeclContext(&SF),
    Context(SF.getASTContext()),
    TokReceiver(SF.shouldKeepSyntaxInfo() ?
                new TokenRecorder(SF) :
                new ConsumeTokenReceiver()),
    SyntaxContext(new SyntaxParsingContext(SyntaxContext, SF, Diags, SourceMgr,
                                           L->getBufferID())) {
  State = PersistentState;
  if (!State) {
    OwnedState.reset(new PersistentParserState());
    State = OwnedState.get();
  }

  // Set the token to a sentinel so that we know the lexer isn't primed yet.
  // This cannot be tok::unknown, since that is a token the lexer could produce.
  Tok.setKind(tok::NUM_TOKENS);

  auto ParserPos = State->takeParserPosition();
  if (ParserPos.isValid() &&
      L->isStateForCurrentBuffer(ParserPos.LS)) {
    restoreParserPosition(ParserPos);
    InPoundLineEnvironment = State->InPoundLineEnvironment;
  }
}
예제 #2
0
파일: Parser.cpp 프로젝트: dkk009/swift
Parser::Parser(std::unique_ptr<Lexer> Lex, SourceFile &SF,
               SILParserState *SIL, PersistentParserState *PersistentState)
  : SourceMgr(SF.getASTContext().SourceMgr),
    Diags(SF.getASTContext().Diags),
    SF(SF),
    L(Lex.release()),
    SIL(SIL),
    CurDeclContext(&SF),
    Context(SF.getASTContext()) {

  State = PersistentState;
  if (!State) {
    OwnedState.reset(new PersistentParserState());
    State = OwnedState.get();
  }

  // Set the token to a sentinel so that we know the lexer isn't primed yet.
  // This cannot be tok::unknown, since that is a token the lexer could produce.
  Tok.setKind(tok::NUM_TOKENS);

  auto ParserPos = State->takeParserPosition();
  if (ParserPos.isValid() &&
      SourceMgr.findBufferContainingLoc(ParserPos.Loc) == L->getBufferID()) {
    auto BeginParserPosition = getParserPosition(ParserPos);
    restoreParserPosition(BeginParserPosition);
    InPoundLineEnvironment = State->InPoundLineEnvironment;
  }
}
예제 #3
0
파일: Parser.cpp 프로젝트: dkk009/swift
Parser::Parser(unsigned BufferID, SourceFile &SF, SILParserState *SIL,
               PersistentParserState *PersistentState)
  : Parser(std::unique_ptr<Lexer>(
             new Lexer(SF.getASTContext().LangOpts, SF.getASTContext().SourceMgr,
                   BufferID, &SF.getASTContext().Diags,
                   /*InSILMode=*/SIL != nullptr,
                   SF.getASTContext().LangOpts.AttachCommentsToDecls
                   ? CommentRetentionMode::AttachToNextToken
                   : CommentRetentionMode::None)), SF, SIL, PersistentState) {
}
예제 #4
0
파일: Parser.cpp 프로젝트: randomstep/swift
Parser::Parser(unsigned BufferID, SourceFile &SF, SILParserTUStateBase *SIL,
               PersistentParserState *PersistentState)
    : Parser(
          std::unique_ptr<Lexer>(new Lexer(
              SF.getASTContext().LangOpts, SF.getASTContext().SourceMgr,
              BufferID, &SF.getASTContext().Diags,
              /*InSILMode=*/SIL != nullptr,
              SF.getASTContext().LangOpts.AttachCommentsToDecls
                  ? CommentRetentionMode::AttachToNextToken
                  : CommentRetentionMode::None,
              SF.shouldKeepSyntaxInfo()
                  ? TriviaRetentionMode::WithTrivia
                  : TriviaRetentionMode::WithoutTrivia)),
          SF, SIL, PersistentState) {}
예제 #5
0
void swift::performWholeModuleTypeChecking(SourceFile &SF) {
  auto &Ctx = SF.getASTContext();
  Ctx.diagnoseAttrsRequiringFoundation(SF);
  Ctx.diagnoseObjCMethodConflicts(SF);
  Ctx.diagnoseObjCUnsatisfiedOptReqConflicts(SF);
  Ctx.diagnoseUnintendedObjCMethodOverrides(SF);
}
예제 #6
0
static SourceLoc getDeclStartPosition(SourceFile &File) {
  SourceManager &SM = File.getASTContext().SourceMgr;
  SourceLoc Winner;

  auto tryUpdateStart = [&](SourceLoc Loc) -> bool {
    if (Loc.isInvalid())
      return false;
    if (Winner.isInvalid()) {
      Winner = Loc;
      return true;
    }
    if (SM.isBeforeInBuffer(Loc, Winner)) {
      Winner = Loc;
      return true;
    }
    return false;
  };

  for (auto D : File.Decls) {
    if (tryUpdateStart(D->getStartLoc())) {
      tryUpdateStart(D->getAttrs().getStartLoc());
      auto RawComment = D->getRawComment();
      if (!RawComment.isEmpty())
        tryUpdateStart(RawComment.Comments.front().Range.getStart());
    }
  }

  return Winner;
}
예제 #7
0
void swift::finishTypeChecking(SourceFile &SF) {
  auto &Ctx = SF.getASTContext();
  TypeChecker TC(Ctx);

  for (auto D : SF.Decls)
    if (auto PD = dyn_cast<ProtocolDecl>(D))
      TC.inferDefaultWitnesses(PD);
}
예제 #8
0
static void printUntilFirstDeclStarts(SourceFile &File, ASTPrinter &Printer) {
  if (!File.getBufferID().hasValue())
    return;
  auto BufferID = *File.getBufferID();

  auto &SM = File.getASTContext().SourceMgr;
  CharSourceRange TextRange = SM.getRangeForBuffer(BufferID);

  auto DeclStartLoc = getDeclStartPosition(File);
  if (DeclStartLoc.isValid()) {
    TextRange = CharSourceRange(SM, TextRange.getStart(), DeclStartLoc);
  }

  Printer << SM.extractText(TextRange, BufferID);
}
예제 #9
0
static void
doCodeCompletion(SourceFile &SF, StringRef EnteredCode, unsigned *BufferID,
                 CodeCompletionCallbacksFactory *CompletionCallbacksFactory) {
    // Temporarily disable printing the diagnostics.
    ASTContext &Ctx = SF.getASTContext();
    auto DiagnosticConsumers = Ctx.Diags.takeConsumers();

    std::string AugmentedCode = EnteredCode.str();
    AugmentedCode += '\0';
    *BufferID = Ctx.SourceMgr.addMemBufferCopy(AugmentedCode, "<REPL Input>");

    const unsigned CodeCompletionOffset = AugmentedCode.size() - 1;

    Ctx.SourceMgr.setCodeCompletionPoint(*BufferID, CodeCompletionOffset);

    // Parse, typecheck and temporarily insert the incomplete code into the AST.
    const unsigned OriginalDeclCount = SF.Decls.size();

    unsigned CurElem = OriginalDeclCount;
    PersistentParserState PersistentState;
    std::unique_ptr<DelayedParsingCallbacks> DelayedCB(
        new CodeCompleteDelayedCallbacks(Ctx.SourceMgr.getCodeCompletionLoc()));
    bool Done;
    do {
        parseIntoSourceFile(SF, *BufferID, &Done, nullptr, &PersistentState,
                            DelayedCB.get());
        performTypeChecking(SF, PersistentState.getTopLevelContext(), None,
                            CurElem);
        CurElem = SF.Decls.size();
    } while (!Done);

    performDelayedParsing(&SF, PersistentState, CompletionCallbacksFactory);

    // Now we are done with code completion.  Remove the declarations we
    // temporarily inserted.
    SF.Decls.resize(OriginalDeclCount);

    // Add the diagnostic consumers back.
    for (auto DC : DiagnosticConsumers)
        Ctx.Diags.addConsumer(*DC);

    Ctx.Diags.resetHadAnyError();
}
예제 #10
0
void REPLCompletions::populate(SourceFile &SF, StringRef EnteredCode) {
    Prefix = "";
    Root.reset();
    CurrentCompletionIdx = ~size_t(0);

    CompletionStrings.clear();
    CookedResults.clear();

    assert(SF.Kind == SourceFileKind::REPL && "Can't append to a non-REPL file");

    unsigned BufferID;
    doCodeCompletion(SF, EnteredCode, &BufferID,
                     CompletionCallbacksFactory.get());

    ASTContext &Ctx = SF.getASTContext();
    std::vector<Token> Tokens = tokenize(Ctx.LangOpts, Ctx.SourceMgr, BufferID);

    if (!Tokens.empty() && Tokens.back().is(tok::code_complete))
        Tokens.pop_back();

    if (!Tokens.empty()) {
        Token &LastToken = Tokens.back();
        if (LastToken.is(tok::identifier) || LastToken.isKeyword()) {
            Prefix = LastToken.getText();

            unsigned Offset = Ctx.SourceMgr.getLocOffsetInBuffer(LastToken.getLoc(),
                              BufferID);

            doCodeCompletion(SF, EnteredCode.substr(0, Offset),
                             &BufferID, CompletionCallbacksFactory.get());
        }
    }

    if (CookedResults.empty())
        State = CompletionState::Empty;
    else if (CookedResults.size() == 1)
        State = CompletionState::Unique;
    else
        State = CompletionState::CompletedRoot;
}
예제 #11
0
void swift::performWholeModuleTypeChecking(SourceFile &SF) {
  auto &Ctx = SF.getASTContext();
  FrontendStatsTracer tracer(Ctx.Stats, "perform-whole-module-type-checking");
  Ctx.diagnoseAttrsRequiringFoundation(SF);
  Ctx.diagnoseObjCMethodConflicts(SF);
  Ctx.diagnoseObjCUnsatisfiedOptReqConflicts(SF);
  Ctx.diagnoseUnintendedObjCMethodOverrides(SF);

  // In whole-module mode, import verification is deferred until all files have
  // been type checked. This avoids caching imported declarations when a valid
  // type checker is not present. The same declaration may need to be fully
  // imported by subsequent files.
  //
  // FIXME: some playgrounds tests (playground_lvalues.swift) fail with
  // verification enabled.
#if 0
  if (SF.Kind != SourceFileKind::REPL &&
      SF.Kind != SourceFileKind::SIL &&
      !Ctx.LangOpts.DebuggerSupport) {
    Ctx.verifyAllLoadedModules();
  }
#endif
}
예제 #12
0
void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC,
                                OptionSet<TypeCheckingFlags> Options,
                                unsigned StartElem,
                                unsigned WarnLongFunctionBodies,
                                unsigned WarnLongExpressionTypeChecking,
                                unsigned ExpressionTimeoutThreshold,
                                unsigned SwitchCheckingInvocationThreshold) {
  if (SF.ASTStage == SourceFile::TypeChecked)
    return;

  auto &Ctx = SF.getASTContext();

  // Make sure we have a type checker.
  TypeChecker &TC = createTypeChecker(Ctx);

  // Make sure that name binding has been completed before doing any type
  // checking.
  performNameBinding(SF, StartElem);

  {
    SharedTimer timer("Type checking / Semantic analysis");

    TC.setWarnLongFunctionBodies(WarnLongFunctionBodies);
    TC.setWarnLongExpressionTypeChecking(WarnLongExpressionTypeChecking);
    if (ExpressionTimeoutThreshold != 0)
      TC.setExpressionTimeoutThreshold(ExpressionTimeoutThreshold);

    if (SwitchCheckingInvocationThreshold != 0)
      TC.setSwitchCheckingInvocationThreshold(
          SwitchCheckingInvocationThreshold);

    if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies))
      TC.enableDebugTimeFunctionBodies();

    if (Options.contains(TypeCheckingFlags::DebugTimeExpressions))
      TC.enableDebugTimeExpressions();

    if (Options.contains(TypeCheckingFlags::ForImmediateMode))
      TC.setInImmediateMode(true);

    // Lookup the swift module.  This ensures that we record all known
    // protocols in the AST.
    (void) TC.getStdlibModule(&SF);

    if (!Ctx.LangOpts.DisableAvailabilityChecking) {
      // Build the type refinement hierarchy for the primary
      // file before type checking.
      TC.buildTypeRefinementContextHierarchy(SF, StartElem);
    }

    // Resolve extensions. This has to occur first during type checking,
    // because the extensions need to be wired into the AST for name lookup
    // to work.
    bindExtensions(SF, TC);

    // Look for bridging functions. This only matters when
    // -enable-source-import is provided.
    checkBridgedFunctions(TC.Context);

    // Type check the top-level elements of the source file.
    bool hasTopLevelCode = false;
    for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
      if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
        hasTopLevelCode = true;
        // Immediately perform global name-binding etc.
        TC.typeCheckTopLevelCodeDecl(TLCD);
      } else {
        TC.typeCheckDecl(D);
      }
    }

    if (hasTopLevelCode) {
      TC.contextualizeTopLevelCode(TLC,
                             llvm::makeArrayRef(SF.Decls).slice(StartElem));
    }

    // If we're in REPL mode, inject temporary result variables and other stuff
    // that the REPL needs to synthesize.
    if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError())
      TC.processREPLTopLevel(SF, TLC, StartElem);

    typeCheckFunctionsAndExternalDecls(SF, TC);
  }

  // Checking that benefits from having the whole module available.
  if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking)) {
    performWholeModuleTypeChecking(SF);
  }

  // Verify that we've checked types correctly.
  SF.ASTStage = SourceFile::TypeChecked;

  {
    SharedTimer timer("AST verification");
    // Verify the SourceFile.
    verify(SF);

    // Verify imported modules.
    //
    // Skip per-file verification in whole-module mode. Verifying imports
    // between files could cause the importer to cache declarations without
    // adding them to the ASTContext. This happens when the importer registers a
    // declaration without a valid TypeChecker instance, as is the case during
    // verification. A subsequent file may require that declaration to be fully
    // imported (e.g. to synthesized a function body), but since it has already
    // been cached, it will never be added to the ASTContext. The solution is to
    // skip verification and avoid caching it.
#ifndef NDEBUG
    if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking) &&
        SF.Kind != SourceFileKind::REPL &&
        SF.Kind != SourceFileKind::SIL &&
        !Ctx.LangOpts.DebuggerSupport) {
      Ctx.verifyAllLoadedModules();
    }
#endif
  }
}
예제 #13
0
void swift::typeCheckExternalDefinitions(SourceFile &SF) {
  assert(SF.ASTStage == SourceFile::TypeChecked);
  auto &Ctx = SF.getASTContext();
  typeCheckFunctionsAndExternalDecls(SF, createTypeChecker(Ctx));
}
예제 #14
0
void swift::performTypeChecking(SourceFile &SF, TopLevelContext &TLC,
                                OptionSet<TypeCheckingFlags> Options,
                                unsigned StartElem,
                                unsigned WarnLongFunctionBodies) {
  if (SF.ASTStage == SourceFile::TypeChecked)
    return;

  auto &Ctx = SF.getASTContext();

  // Make sure we have a type checker.
  Optional<TypeChecker> MyTC;
  if (!Ctx.getLazyResolver())
    MyTC.emplace(Ctx);

  // Make sure that name binding has been completed before doing any type
  // checking.
  {
    SharedTimer timer("Name binding");
    performNameBinding(SF, StartElem);
  }

  {
    // NOTE: The type checker is scoped to be torn down before AST
    // verification.
    SharedTimer timer("Type checking / Semantic analysis");

    if (MyTC) {
      MyTC->setWarnLongFunctionBodies(WarnLongFunctionBodies);
      if (Options.contains(TypeCheckingFlags::DebugTimeFunctionBodies))
        MyTC->enableDebugTimeFunctionBodies();

      if (Options.contains(TypeCheckingFlags::DebugTimeExpressions))
        MyTC->enableDebugTimeExpressions();

      if (Options.contains(TypeCheckingFlags::ForImmediateMode))
        MyTC->setInImmediateMode(true);
      
      // Lookup the swift module.  This ensures that we record all known
      // protocols in the AST.
      (void) MyTC->getStdlibModule(&SF);

      if (!Ctx.LangOpts.DisableAvailabilityChecking) {
        // Build the type refinement hierarchy for the primary
        // file before type checking.
        MyTC->buildTypeRefinementContextHierarchy(SF, StartElem);
      }
    }

    TypeChecker &TC =
      MyTC ? *MyTC : *static_cast<TypeChecker *>(Ctx.getLazyResolver());

    // Resolve extensions. This has to occur first during type checking,
    // because the extensions need to be wired into the AST for name lookup
    // to work.
    // FIXME: We can have interesting ordering dependencies among the various
    // extensions, so we'll need to be smarter here.
    // FIXME: The current source file needs to be handled specially, because of
    // private extensions.
    SF.forAllVisibleModules([&](ModuleDecl::ImportedModule import) {
      // FIXME: Respect the access path?
      for (auto file : import.second->getFiles()) {
        auto SF = dyn_cast<SourceFile>(file);
        if (!SF)
          continue;

        for (auto D : SF->Decls) {
          if (auto ED = dyn_cast<ExtensionDecl>(D))
            bindExtensionDecl(ED, TC);
        }
      }
    });

    // FIXME: Check for cycles in class inheritance here?
    
    // Type check the top-level elements of the source file.
    for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
      if (isa<TopLevelCodeDecl>(D))
        continue;

      TC.typeCheckDecl(D, /*isFirstPass*/true);
    }

    // At this point, we can perform general name lookup into any type.

    // We don't know the types of all the global declarations in the first
    // pass, which means we can't completely analyze everything. Perform the
    // second pass now.

    bool hasTopLevelCode = false;
    for (auto D : llvm::makeArrayRef(SF.Decls).slice(StartElem)) {
      if (TopLevelCodeDecl *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
        hasTopLevelCode = true;
        // Immediately perform global name-binding etc.
        TC.typeCheckTopLevelCodeDecl(TLCD);
      } else {
        TC.typeCheckDecl(D, /*isFirstPass*/false);
      }
    }

    if (hasTopLevelCode) {
      TC.contextualizeTopLevelCode(TLC,
                             llvm::makeArrayRef(SF.Decls).slice(StartElem));
    }

    // If we're in REPL mode, inject temporary result variables and other stuff
    // that the REPL needs to synthesize.
    if (SF.Kind == SourceFileKind::REPL && !Ctx.hadError())
      TC.processREPLTopLevel(SF, TLC, StartElem);

    typeCheckFunctionsAndExternalDecls(TC);
  }
  MyTC.reset();

  // Checking that benefits from having the whole module available.
  if (!(Options & TypeCheckingFlags::DelayWholeModuleChecking)) {
    performWholeModuleTypeChecking(SF);
  }

  // Verify that we've checked types correctly.
  SF.ASTStage = SourceFile::TypeChecked;

  {
    SharedTimer timer("AST verification");
    // Verify the SourceFile.
    verify(SF);

    // Verify imported modules.
#ifndef NDEBUG
    if (SF.Kind != SourceFileKind::REPL &&
        SF.Kind != SourceFileKind::SIL &&
        !Ctx.LangOpts.DebuggerSupport) {
      Ctx.verifyAllLoadedModules();
    }
#endif
  }
}