diff --git a/include/swift/IDE/SyntaxModel.h b/include/swift/IDE/SyntaxModel.h index 60b8c69e55e..1d4c1c662c9 100644 --- a/include/swift/IDE/SyntaxModel.h +++ b/include/swift/IDE/SyntaxModel.h @@ -32,6 +32,8 @@ enum class SyntaxNodeKind : uint8_t { Integer, Floating, String, + /// Marks the parens for a string interpolation. + StringInterpolationAnchor, Character, CommentLine, CommentBlock, diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 5d64093e9a7..4f72df45c19 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -56,7 +56,8 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile) /*TokenizeInterpolatedString=*/true); std::vector Nodes; SourceLoc AttrLoc; - for (auto &Tok : Tokens) { + for (unsigned I = 0, E = Tokens.size(); I != E; ++I) { + auto &Tok = Tokens[I]; SyntaxNodeKind Kind; SourceLoc Loc; Optional Length; @@ -100,6 +101,35 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile) // attribute name. AttrLoc = Tok.getLoc(); continue; + + case tok::l_paren: { + // Check if this is a string interpolation paren. + if (I == 0) + continue; + auto &PrevTok = Tokens[I-1]; + if (PrevTok.getKind() != tok::string_literal) + continue; + StringRef StrText = PrevTok.getText(); + if (StrText.size() > 1 && StrText.back() == '\"') + continue; + Kind = SyntaxNodeKind::StringInterpolationAnchor; + break; + } + + case tok::r_paren: { + // Check if this is a string interpolation paren. + if (I+1 == E) + continue; + auto &NextTok = Tokens[I+1]; + if (NextTok.getKind() != tok::string_literal) + continue; + StringRef StrText = NextTok.getText(); + if (StrText.size() > 1 && StrText.front() == '\"') + continue; + Kind = SyntaxNodeKind::StringInterpolationAnchor; + break; + } + default: continue; } diff --git a/test/IDE/coloring.swift b/test/IDE/coloring.swift index 7a173b8bf16..20fdb64e34d 100644 --- a/test/IDE/coloring.swift +++ b/test/IDE/coloring.swift @@ -173,7 +173,7 @@ func genFn(_: T) -> Int {} func f(x: Int) -> Int { // CHECK: // string interpolation is the best // string interpolation is the best - // CHECK: "This is string \(genFn({(a:Int -> Int) in a})) interpolation" + // CHECK: "This is string \(genFn({(a:Int -> Int) in a})) interpolation" "This is string \(genFn({(a:Int -> Int) in a})) interpolation" } @@ -194,7 +194,7 @@ func test() { typealias MyInt = Int func test2(x: Int) { - // CHECK: "\(x)" + // CHECK: "\(x)" "\(x)" } diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index 5bf433f0eec..d6bd550bb2f 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -610,6 +610,7 @@ public: case SyntaxNodeKind::Integer: Id = "int"; break; case SyntaxNodeKind::Floating: Id = "float"; break; case SyntaxNodeKind::String: Id = "str"; break; + case SyntaxNodeKind::StringInterpolationAnchor: Id = "anchor"; break; case SyntaxNodeKind::Character: Id = "char"; break; case SyntaxNodeKind::CommentLine: Id = "comment-line"; break; case SyntaxNodeKind::CommentBlock: Id = "comment-block"; break; @@ -635,6 +636,7 @@ public: case SyntaxNodeKind::Integer: Col = llvm::raw_ostream::BLUE; break; case SyntaxNodeKind::Floating: Col = llvm::raw_ostream::BLUE; break; case SyntaxNodeKind::String: Col = llvm::raw_ostream::RED; break; + case SyntaxNodeKind::StringInterpolationAnchor: Col = llvm::raw_ostream::CYAN; break; case SyntaxNodeKind::Character: Col = llvm::raw_ostream::BLUE; break; case SyntaxNodeKind::CommentLine: Col = llvm::raw_ostream::GREEN; break; case SyntaxNodeKind::CommentBlock: Col = llvm::raw_ostream::GREEN; break;