Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strip comments from inlinable text when printing in swiftinterface files #69358

Merged
merged 6 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 57 additions & 15 deletions lib/AST/InlinableText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,41 +189,83 @@ struct ExtractInactiveRanges : public ASTWalker {
};
} // end anonymous namespace

static void appendRange(
harlanhaskins marked this conversation as resolved.
Show resolved Hide resolved
SourceManager &sourceMgr, SourceLoc start, SourceLoc end,
SmallVectorImpl<char> &scratch) {
unsigned bufferID = sourceMgr.findBufferContainingLoc(start);
unsigned offset = sourceMgr.getLocOffsetInBuffer(start, bufferID);
unsigned endOffset = sourceMgr.getLocOffsetInBuffer(end, bufferID);

// Strip comments from the chunk before adding it by re-lexing the range.
LangOptions FakeLangOpts;
Lexer lexer(FakeLangOpts, sourceMgr, bufferID, nullptr, LexerMode::Swift,
HashbangMode::Disallowed, CommentRetentionMode::ReturnAsTokens,
offset, endOffset);

SourceLoc nonCommentStart = start;
Token token;

// Re-lex the range, and skip the full text of `tok::comment` tokens.
while (!token.is(tok::eof)) {
lexer.lex(token);

if (token.is(tok::comment)) {
// Append the range from the last non-comment token to the beginning of this comment
// token.
SourceLoc commentLoc = token.getLoc();
auto charRange = CharSourceRange(sourceMgr, nonCommentStart, commentLoc);
StringRef text = sourceMgr.extractText(charRange);
scratch.append(text.begin(), text.end());

// Append a single whitespace character, to avoid fusing tokens.
scratch.push_back(' ');
harlanhaskins marked this conversation as resolved.
Show resolved Hide resolved

// Set the start of the next non-comment range to the end of this token.
SourceLoc endLoc = Lexer::getLocForEndOfToken(sourceMgr, token.getLoc());

// The comment token's end location includes trailing whitespace, so trim trailing
// whitespace and only strip the portions of the comment that are not whitespace.
harlanhaskins marked this conversation as resolved.
Show resolved Hide resolved
CharSourceRange range = CharSourceRange(sourceMgr, commentLoc, endLoc);
StringRef commentText = sourceMgr.extractText(range);
unsigned whitespaceOffset = commentText.size() - commentText.rtrim().size();
if (whitespaceOffset > 0) {
endLoc = endLoc.getAdvancedLoc(-whitespaceOffset);
}

nonCommentStart = endLoc;
}
}

if (nonCommentStart.isValid() && nonCommentStart != end) {
auto charRange = CharSourceRange(sourceMgr, nonCommentStart, end);
StringRef text = sourceMgr.extractText(charRange);
scratch.append(text.begin(), text.end());
}
}

StringRef swift::extractInlinableText(SourceManager &sourceMgr, ASTNode node,
SmallVectorImpl<char> &scratch) {
// Extract inactive ranges from the text of the node.
ExtractInactiveRanges extractor(sourceMgr);
node.walk(extractor);

// If there were no inactive ranges, then there were no #if configs.
// Return an unowned buffer directly into the source file.
if (extractor.ranges.empty()) {
harlanhaskins marked this conversation as resolved.
Show resolved Hide resolved
auto range =
Lexer::getCharSourceRangeFromSourceRange(
sourceMgr, node.getSourceRange());
return sourceMgr.extractText(range);
}

// Begin piecing together active code ranges.

// Get the full start and end of the provided node, as character locations.
SourceLoc start = node.getStartLoc();
SourceLoc end = Lexer::getLocForEndOfToken(sourceMgr, node.getEndLoc());
for (auto &range : extractor.getSortedRanges()) {
// Add the text from the current 'start' to this ignored range's start.
auto charRange = CharSourceRange(sourceMgr, start, range.getStart());
auto chunk = sourceMgr.extractText(charRange);
scratch.append(chunk.begin(), chunk.end());
appendRange(sourceMgr, start, range.getStart(), scratch);

// Set 'start' to the end of this range, effectively skipping it.
start = range.getEnd();
}

// If there's leftover unignored text, add it.
if (start != end) {
auto range = CharSourceRange(sourceMgr, start, end);
auto chunk = sourceMgr.extractText(range);
scratch.append(chunk.begin(), chunk.end());
appendRange(sourceMgr, start, end, scratch);
}

return { scratch.data(), scratch.size() };
}
30 changes: 30 additions & 0 deletions test/ModuleInterface/if-configs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,33 @@ public func hasIfCompilerCheck(_ x: () -> Bool = {
#endif
}) {
}

// CHECK: func hasComments
// CHECK: print(
// CHECK-NOT: comment! don't mess up indentation!
// CHECK: {{^}} """
// CHECK: {{^}} """
// CHECK-NOT: #if
// CHECK-NOT: comment!
// CHECK: return true
public func hasComments() -> Bool {
/* comment! */ // comment!
harlanhaskins marked this conversation as resolved.
Show resolved Hide resolved
#if NOT_PROVIDED
// comment!
return true
#endif

print(/*
comment!
*/"this should show up")

print(
// comment! don't mess up indentation!
"""
""")

#if !NOT_PROVIDED
// comment!
return/* comment! */true/* comment! */
#endif
}