|
46 | 46 | #include "swift/IDE/IDERequests.h"
|
47 | 47 | #include "swift/Index/Index.h"
|
48 | 48 | #include "swift/Sema/IDETypeChecking.h"
|
| 49 | +#include "swift/SyntaxParse/SyntaxTreeCreator.h" |
49 | 50 | #include "swift/Markup/Markup.h"
|
50 | 51 | #include "swift/Config.h"
|
51 | 52 | #include "clang/Rewrite/Core/RewriteBuffer.h"
|
@@ -717,25 +718,35 @@ removeCodeCompletionTokens(llvm::MemoryBuffer *Input,
|
717 | 718 | Input->getBufferIdentifier()));
|
718 | 719 | }
|
719 | 720 |
|
| 721 | +/// Returns true on error |
| 722 | +static bool setBufferForFile(StringRef SourceFilename, |
| 723 | + std::unique_ptr<llvm::MemoryBuffer> &Buffer) { |
| 724 | + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
| 725 | + llvm::MemoryBuffer::getFile(SourceFilename); |
| 726 | + if (!FileBufOrErr) { |
| 727 | + llvm::errs() << "error opening input file '" << SourceFilename << "':\n" |
| 728 | + << " " << FileBufOrErr.getError().message() << '\n'; |
| 729 | + return true; |
| 730 | + } |
| 731 | + Buffer = std::move(FileBufOrErr.get()); |
| 732 | + return false; |
| 733 | +} |
| 734 | + |
720 | 735 | static bool doCodeCompletionImpl(
|
721 | 736 | CodeCompletionCallbacksFactory *callbacksFactory,
|
722 | 737 | const CompilerInvocation &InitInvok,
|
723 | 738 | StringRef SourceFilename,
|
724 | 739 | StringRef SecondSourceFileName,
|
725 | 740 | StringRef CodeCompletionToken,
|
726 | 741 | bool CodeCompletionDiagnostics) {
|
727 |
| - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
728 |
| - llvm::MemoryBuffer::getFile(SourceFilename); |
729 |
| - if (!FileBufOrErr) { |
730 |
| - llvm::errs() << "error opening input file: " |
731 |
| - << FileBufOrErr.getError().message() << '\n'; |
| 742 | + std::unique_ptr<llvm::MemoryBuffer> FileBuf; |
| 743 | + if (setBufferForFile(SourceFilename, FileBuf)) |
732 | 744 | return 1;
|
733 |
| - } |
734 | 745 |
|
735 | 746 | unsigned Offset;
|
736 | 747 |
|
737 | 748 | std::unique_ptr<llvm::MemoryBuffer> CleanFile(removeCodeCompletionTokens(
|
738 |
| - FileBufOrErr.get().get(), CodeCompletionToken, &Offset)); |
| 749 | + FileBuf.get(), CodeCompletionToken, &Offset)); |
739 | 750 |
|
740 | 751 | if (Offset == ~0U) {
|
741 | 752 | llvm::errs() << "could not find code completion token \""
|
@@ -843,15 +854,11 @@ static int doCodeCompletion(const CompilerInvocation &InitInvok,
|
843 | 854 |
|
844 | 855 | static int doREPLCodeCompletion(const CompilerInvocation &InitInvok,
|
845 | 856 | StringRef SourceFilename) {
|
846 |
| - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
847 |
| - llvm::MemoryBuffer::getFile(SourceFilename); |
848 |
| - if (!FileBufOrErr) { |
849 |
| - llvm::errs() << "error opening input file: " |
850 |
| - << FileBufOrErr.getError().message() << '\n'; |
| 857 | + std::unique_ptr<llvm::MemoryBuffer> FileBuf; |
| 858 | + if (setBufferForFile(SourceFilename, FileBuf)) |
851 | 859 | return 1;
|
852 |
| - } |
853 | 860 |
|
854 |
| - StringRef BufferText = FileBufOrErr.get()->getBuffer(); |
| 861 | + StringRef BufferText = FileBuf->getBuffer(); |
855 | 862 | // Drop a single newline character from the buffer.
|
856 | 863 | if (BufferText.endswith("\n"))
|
857 | 864 | BufferText = BufferText.drop_back(1);
|
@@ -1057,38 +1064,74 @@ static int doSyntaxColoring(const CompilerInvocation &InitInvok,
|
1057 | 1064 | CompilerInvocation Invocation(InitInvok);
|
1058 | 1065 | Invocation.getFrontendOptions().InputsAndOutputs.addInputFile(SourceFilename);
|
1059 | 1066 | Invocation.getLangOptions().DisableAvailabilityChecking = false;
|
1060 |
| - |
1061 |
| - CompilerInstance CI; |
1062 |
| - |
1063 |
| - // Display diagnostics to stderr. |
1064 |
| - PrintingDiagnosticConsumer PrintDiags; |
1065 |
| - CI.addDiagnosticConsumer(&PrintDiags); |
1066 | 1067 | Invocation.getLangOptions().Playground = Playground;
|
1067 | 1068 | Invocation.getLangOptions().CollectParsedToken = true;
|
1068 | 1069 | Invocation.getLangOptions().BuildSyntaxTree = true;
|
1069 |
| - if (CI.setup(Invocation)) |
1070 |
| - return 1; |
1071 |
| - registerIDERequestFunctions(CI.getASTContext().evaluator); |
1072 |
| - if (!RunTypeChecker) |
1073 |
| - CI.performParseOnly(); |
1074 |
| - else |
| 1070 | + |
| 1071 | + // Display diagnostics to stderr. |
| 1072 | + PrintingDiagnosticConsumer PrintDiags; |
| 1073 | + |
| 1074 | + if (RunTypeChecker) { |
| 1075 | + CompilerInstance CI; |
| 1076 | + CI.addDiagnosticConsumer(&PrintDiags); |
| 1077 | + if (CI.setup(Invocation)) |
| 1078 | + return 1; |
1075 | 1079 | CI.performSema();
|
1076 | 1080 |
|
1077 |
| - unsigned BufID = CI.getInputBufferIDs().back(); |
1078 |
| - SourceFile *SF = nullptr; |
1079 |
| - for (auto Unit : CI.getMainModule()->getFiles()) { |
1080 |
| - SF = dyn_cast<SourceFile>(Unit); |
1081 |
| - if (SF) |
1082 |
| - break; |
1083 |
| - } |
1084 |
| - assert(SF && "no source file?"); |
| 1081 | + unsigned BufID = CI.getInputBufferIDs().back(); |
| 1082 | + SourceFile *SF = nullptr; |
| 1083 | + for (auto Unit : CI.getMainModule()->getFiles()) { |
| 1084 | + SF = dyn_cast<SourceFile>(Unit); |
| 1085 | + if (SF) |
| 1086 | + break; |
| 1087 | + } |
| 1088 | + assert(SF && "no source file?"); |
| 1089 | + |
| 1090 | + ide::SyntaxModelContext ColorContext(*SF); |
| 1091 | + PrintSyntaxColorWalker ColorWalker(CI.getSourceMgr(), BufID, llvm::outs(), |
| 1092 | + TerminalOutput); |
| 1093 | + ColorContext.walk(ColorWalker); |
| 1094 | + ColorWalker.finished(); |
| 1095 | + } else { |
| 1096 | + // SourceKit doesn't set up a compiler instance at all for its syntactic |
| 1097 | + // requests, just the parser. We try to mimic that setup here to help catch |
| 1098 | + // any cases where the walker might inadvertently rely on the name lookup or |
| 1099 | + // other semantic functionality via the request evaluator. |
| 1100 | + std::unique_ptr<llvm::MemoryBuffer> FileBuf; |
| 1101 | + if (setBufferForFile(SourceFilename, FileBuf)) |
| 1102 | + return 1; |
| 1103 | + |
| 1104 | + SourceManager SM; |
| 1105 | + unsigned BufferID = SM.addNewSourceBuffer(std::move(FileBuf)); |
1085 | 1106 |
|
1086 |
| - ide::SyntaxModelContext ColorContext(*SF); |
1087 |
| - PrintSyntaxColorWalker ColorWalker(CI.getSourceMgr(), BufID, llvm::outs(), |
1088 |
| - TerminalOutput); |
1089 |
| - ColorContext.walk(ColorWalker); |
1090 |
| - ColorWalker.finished(); |
| 1107 | + RC<SyntaxArena> syntaxArena{new syntax::SyntaxArena()}; |
| 1108 | + std::shared_ptr<SyntaxTreeCreator> SynTreeCreator = |
| 1109 | + std::make_shared<SyntaxTreeCreator>( |
| 1110 | + SM, BufferID, Invocation.getMainFileSyntaxParsingCache(), |
| 1111 | + syntaxArena); |
1091 | 1112 |
|
| 1113 | + ParserUnit Parser(SM, SourceFileKind::Main, BufferID, |
| 1114 | + Invocation.getLangOptions(), |
| 1115 | + Invocation.getTypeCheckerOptions(), |
| 1116 | + Invocation.getModuleName(), |
| 1117 | + SynTreeCreator, |
| 1118 | + Invocation.getMainFileSyntaxParsingCache()); |
| 1119 | + |
| 1120 | + registerParseRequestFunctions(Parser.getParser().Context.evaluator); |
| 1121 | + registerTypeCheckerRequestFunctions(Parser.getParser().Context.evaluator); |
| 1122 | + |
| 1123 | + // Collecting syntactic information shouldn't evaluate # conditions. |
| 1124 | + Parser.getParser().State->PerformConditionEvaluation = false; |
| 1125 | + Parser.getDiagnosticEngine().addConsumer(PrintDiags); |
| 1126 | + |
| 1127 | + (void)Parser.parse(); |
| 1128 | + |
| 1129 | + ide::SyntaxModelContext ColorContext(Parser.getSourceFile()); |
| 1130 | + PrintSyntaxColorWalker ColorWalker(SM, BufferID, llvm::outs(), |
| 1131 | + TerminalOutput); |
| 1132 | + ColorContext.walk(ColorWalker); |
| 1133 | + ColorWalker.finished(); |
| 1134 | + } |
1092 | 1135 | return 0;
|
1093 | 1136 | }
|
1094 | 1137 |
|
@@ -1280,25 +1323,51 @@ class StructureAnnotator : public ide::SyntaxModelWalker {
|
1280 | 1323 |
|
1281 | 1324 | static int doStructureAnnotation(const CompilerInvocation &InitInvok,
|
1282 | 1325 | StringRef SourceFilename) {
|
| 1326 | + std::unique_ptr<llvm::MemoryBuffer> FileBuf; |
| 1327 | + if (setBufferForFile(SourceFilename, FileBuf)) |
| 1328 | + return 1; |
| 1329 | + |
1283 | 1330 | CompilerInvocation Invocation(InitInvok);
|
1284 | 1331 | Invocation.getLangOptions().BuildSyntaxTree = true;
|
1285 | 1332 | Invocation.getLangOptions().CollectParsedToken = true;
|
1286 | 1333 | Invocation.getFrontendOptions().InputsAndOutputs.addInputFile(SourceFilename);
|
1287 | 1334 |
|
1288 |
| - CompilerInstance CI; |
| 1335 | + // Structure annotation is run as a purely syntactic request by SourceKit. It |
| 1336 | + // doesn't set up a compiler instance at all, just the parser. We try to mimic |
| 1337 | + // that setup here to help catch any cases where the walker might inadvertently |
| 1338 | + // rely on the name lookup or other semantic functionality via the request |
| 1339 | + // evaluator. |
| 1340 | + SourceManager SM; |
| 1341 | + unsigned BufferID = SM.addNewSourceBuffer(std::move(FileBuf)); |
| 1342 | + |
| 1343 | + RC<SyntaxArena> syntaxArena{new syntax::SyntaxArena()}; |
| 1344 | + std::shared_ptr<SyntaxTreeCreator> SynTreeCreator = |
| 1345 | + std::make_shared<SyntaxTreeCreator>( |
| 1346 | + SM, BufferID, Invocation.getMainFileSyntaxParsingCache(), |
| 1347 | + syntaxArena); |
| 1348 | + |
| 1349 | + ParserUnit Parser(SM, SourceFileKind::Main, BufferID, |
| 1350 | + Invocation.getLangOptions(), |
| 1351 | + Invocation.getTypeCheckerOptions(), |
| 1352 | + Invocation.getModuleName(), |
| 1353 | + SynTreeCreator, |
| 1354 | + Invocation.getMainFileSyntaxParsingCache()); |
| 1355 | + |
| 1356 | + registerParseRequestFunctions(Parser.getParser().Context.evaluator); |
| 1357 | + registerTypeCheckerRequestFunctions( |
| 1358 | + Parser.getParser().Context.evaluator); |
| 1359 | + |
| 1360 | + // Collecting syntactic information shouldn't evaluate # conditions. |
| 1361 | + Parser.getParser().State->PerformConditionEvaluation = false; |
1289 | 1362 |
|
1290 | 1363 | // Display diagnostics to stderr.
|
1291 | 1364 | PrintingDiagnosticConsumer PrintDiags;
|
1292 |
| - CI.addDiagnosticConsumer(&PrintDiags); |
1293 |
| - if (CI.setup(Invocation)) |
1294 |
| - return 1; |
1295 |
| - registerIDERequestFunctions(CI.getASTContext().evaluator); |
1296 |
| - CI.performParseOnly(); |
| 1365 | + Parser.getDiagnosticEngine().addConsumer(PrintDiags); |
1297 | 1366 |
|
1298 |
| - unsigned BufID = CI.getInputBufferIDs().back(); |
1299 |
| - ide::SyntaxModelContext StructureContext( |
1300 |
| - CI.getMainModule()->getMainSourceFile(SourceFileKind::Main)); |
1301 |
| - StructureAnnotator Annotator(CI.getSourceMgr(), BufID); |
| 1367 | + (void)Parser.parse(); |
| 1368 | + |
| 1369 | + ide::SyntaxModelContext StructureContext(Parser.getSourceFile()); |
| 1370 | + StructureAnnotator Annotator(SM, BufferID); |
1302 | 1371 | StructureContext.walk(Annotator);
|
1303 | 1372 | Annotator.printResult(llvm::outs());
|
1304 | 1373 | return 0;
|
@@ -1561,17 +1630,13 @@ static int doSemanticAnnotation(const CompilerInvocation &InitInvok,
|
1561 | 1630 | }
|
1562 | 1631 |
|
1563 | 1632 | static int doInputCompletenessTest(StringRef SourceFilename) {
|
1564 |
| - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
1565 |
| - llvm::MemoryBuffer::getFile(SourceFilename); |
1566 |
| - if (!FileBufOrErr) { |
1567 |
| - llvm::errs() << "error opening input file: " |
1568 |
| - << FileBufOrErr.getError().message() << '\n'; |
| 1633 | + std::unique_ptr<llvm::MemoryBuffer> FileBuf; |
| 1634 | + if (setBufferForFile(SourceFilename, FileBuf)) |
1569 | 1635 | return 1;
|
1570 |
| - } |
1571 | 1636 |
|
1572 | 1637 | llvm::raw_ostream &OS = llvm::outs();
|
1573 | 1638 | OS << SourceFilename << ": ";
|
1574 |
| - if (isSourceInputComplete(std::move(FileBufOrErr.get()), |
| 1639 | + if (isSourceInputComplete(std::move(FileBuf), |
1575 | 1640 | SourceFileKind::REPL).IsComplete) {
|
1576 | 1641 | OS << "IS_COMPLETE\n";
|
1577 | 1642 | } else {
|
@@ -3102,16 +3167,12 @@ static int doTestCreateCompilerInvocation(ArrayRef<const char *> Args) {
|
3102 | 3167 | }
|
3103 | 3168 |
|
3104 | 3169 | static int doTestCompilerInvocationFromModule(StringRef ModuleFilePath) {
|
3105 |
| - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
3106 |
| - llvm::MemoryBuffer::getFile(ModuleFilePath); |
3107 |
| - if (!FileBufOrErr) { |
3108 |
| - llvm::errs() << "error opening input file: " |
3109 |
| - << FileBufOrErr.getError().message() << '\n'; |
3110 |
| - return -1; |
3111 |
| - } |
| 3170 | + std::unique_ptr<llvm::MemoryBuffer> FileBuf; |
| 3171 | + if (setBufferForFile(ModuleFilePath, FileBuf)) |
| 3172 | + return 1; |
3112 | 3173 |
|
3113 | 3174 | CompilerInvocation CI;
|
3114 |
| - StringRef Data = FileBufOrErr.get()->getBuffer(); |
| 3175 | + StringRef Data = FileBuf->getBuffer(); |
3115 | 3176 | static_assert(static_cast<int>(serialization::Status::Valid) == 0,
|
3116 | 3177 | "Status::Valid should be a successful exit");
|
3117 | 3178 | return static_cast<int>(CI.loadFromSerializedAST(Data));
|
|
0 commit comments