[clang] 0e480b3 - Revert "[libTooling] Add function to determine associated text of a declaration."
Nico Weber via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 25 16:22:29 PST 2020
Author: Nico Weber
Date: 2020-02-25T19:21:52-05:00
New Revision: 0e480b39c66143ad142f9a30d8d40e49d7d7b0ce
URL: https://github.com/llvm/llvm-project/commit/0e480b39c66143ad142f9a30d8d40e49d7d7b0ce
DIFF: https://github.com/llvm/llvm-project/commit/0e480b39c66143ad142f9a30d8d40e49d7d7b0ce.diff
LOG: Revert "[libTooling] Add function to determine associated text of a declaration."
This reverts commit 9c54f6154f748e707ad2385ddf6d66e812890c6a.
Breaks two tests on Windows, see e.g.
http://lab.llvm.org:8011/builders/clang-x64-windows-msvc/builds/14505/steps/stage%201%20check/logs/stdio
Added:
Modified:
clang/include/clang/Tooling/Transformer/SourceCode.h
clang/lib/Tooling/Transformer/SourceCode.cpp
clang/unittests/Tooling/SourceCodeTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Tooling/Transformer/SourceCode.h b/clang/include/clang/Tooling/Transformer/SourceCode.h
index 2c7eb65371cf..1b92a117f44c 100644
--- a/clang/include/clang/Tooling/Transformer/SourceCode.h
+++ b/clang/include/clang/Tooling/Transformer/SourceCode.h
@@ -20,10 +20,9 @@
namespace clang {
namespace tooling {
-/// Extends \p Range to include the token \p Terminator, if it immediately
-/// follows the end of the range. Otherwise, returns \p Range unchanged.
-CharSourceRange maybeExtendRange(CharSourceRange Range,
- tok::TokenKind Terminator,
+/// Extends \p Range to include the token \p Next, if it immediately follows the
+/// end of the range. Otherwise, returns \p Range unchanged.
+CharSourceRange maybeExtendRange(CharSourceRange Range, tok::TokenKind Next,
ASTContext &Context);
/// Returns the source range spanning the node, extended to include \p Next, if
@@ -36,13 +35,6 @@ CharSourceRange getExtendedRange(const T &Node, tok::TokenKind Next,
Next, Context);
}
-/// Returns the logical source range of the node extended to include associated
-/// comments and whitespace before and after the node, and associated
-/// terminators. The returned range consists of file locations, if valid file
-/// locations can be found for the associated content; otherwise, an invalid
-/// range is returned.
-CharSourceRange getAssociatedRange(const Decl &D, ASTContext &Context);
-
/// Returns the source-code text in the specified range.
StringRef getText(CharSourceRange Range, const ASTContext &Context);
diff --git a/clang/lib/Tooling/Transformer/SourceCode.cpp b/clang/lib/Tooling/Transformer/SourceCode.cpp
index 8d59487ea7ae..5c1f8b46fe42 100644
--- a/clang/lib/Tooling/Transformer/SourceCode.cpp
+++ b/clang/lib/Tooling/Transformer/SourceCode.cpp
@@ -10,13 +10,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Transformer/SourceCode.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/Comment.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/Errc.h"
@@ -91,302 +84,3 @@ clang::tooling::getRangeForEdit(const CharSourceRange &EditRange,
return Range;
}
-
-static bool startsWithNewline(const SourceManager &SM, const Token &Tok) {
- return isVerticalWhitespace(SM.getCharacterData(Tok.getLocation())[0]);
-}
-
-static bool contains(const std::set<tok::TokenKind> &Terminators,
- const Token &Tok) {
- return Terminators.count(Tok.getKind()) > 0;
-}
-
-// Returns the exclusive, *file* end location of the entity whose last token is
-// at location 'EntityLast'. That is, it returns the location one past the last
-// relevant character.
-//
-// Associated tokens include comments, horizontal whitespace and 'Terminators'
-// -- optional tokens, which, if any are found, will be included; if
-// 'Terminators' is empty, we will not include any extra tokens beyond comments
-// and horizontal whitespace.
-static SourceLocation
-getEntityEndLoc(const SourceManager &SM, SourceLocation EntityLast,
- const std::set<tok::TokenKind> &Terminators,
- const LangOptions &LangOpts) {
- assert(EntityLast.isValid() && "Invalid end location found.");
-
- // We remember the last location of a non-horizontal-whitespace token we have
- // lexed; this is the location up to which we will want to delete.
- // FIXME: Support using the spelling loc here for cases where we want to
- // analyze the macro text.
-
- CharSourceRange ExpansionRange = SM.getExpansionRange(EntityLast);
- // FIXME: Should check isTokenRange(), for the (rare) case that
- // `ExpansionRange` is a character range.
- std::unique_ptr<Lexer> Lexer = [&]() {
- bool Invalid = false;
- auto FileOffset = SM.getDecomposedLoc(ExpansionRange.getEnd());
- llvm::StringRef File = SM.getBufferData(FileOffset.first, &Invalid);
- assert(!Invalid && "Cannot get file/offset");
- return std::make_unique<clang::Lexer>(
- SM.getLocForStartOfFile(FileOffset.first), LangOpts, File.begin(),
- File.data() + FileOffset.second, File.end());
- }();
-
- // Tell Lexer to return whitespace as pseudo-tokens (kind is tok::unknown).
- Lexer->SetKeepWhitespaceMode(true);
-
- // Generally, the code we want to include looks like this ([] are optional),
- // If Terminators is empty:
- // [ <comment> ] [ <newline> ]
- // Otherwise:
- // ... <terminator> [ <comment> ] [ <newline> ]
-
- Token Tok;
- bool Terminated = false;
-
- // First, lex to the current token (which is the last token of the range that
- // is definitely associated with the decl). Then, we process the first token
- // separately from the rest based on conditions that hold specifically for
- // that first token.
- //
- // We do not search for a terminator if none is required or we've already
- // encountered it. Otherwise, if the original `EntityLast` location was in a
- // macro expansion, we don't have visibility into the text, so we assume we've
- // already terminated. However, we note this assumption with
- // `TerminatedByMacro`, because we'll want to handle it somewhat
diff erently
- // for the terminators semicolon and comma. These terminators can be safely
- // associated with the entity when they appear after the macro -- extra
- // semicolons have no effect on the program and a well-formed program won't
- // have multiple commas in a row, so we're guaranteed that there is only one.
- //
- // FIXME: This handling of macros is more conservative than necessary. When
- // the end of the expansion coincides with the end of the node, we can still
- // safely analyze the code. But, it is more complicated, because we need to
- // start by lexing the spelling loc for the first token and then switch to the
- // expansion loc.
- bool TerminatedByMacro = false;
- Lexer->LexFromRawLexer(Tok);
- if (Terminators.empty() || contains(Terminators, Tok))
- Terminated = true;
- else if (EntityLast.isMacroID()) {
- Terminated = true;
- TerminatedByMacro = true;
- }
-
- // We save the most recent candidate for the exclusive end location.
- SourceLocation End = Tok.getEndLoc();
-
- while (!Terminated) {
- // Lex the next token we want to possibly expand the range with.
- Lexer->LexFromRawLexer(Tok);
-
- switch (Tok.getKind()) {
- case tok::eof:
- // Unexpected separators.
- case tok::l_brace:
- case tok::r_brace:
- case tok::comma:
- return End;
- // Whitespace pseudo-tokens.
- case tok::unknown:
- if (startsWithNewline(SM, Tok))
- // Include at least until the end of the line.
- End = Tok.getEndLoc();
- break;
- default:
- if (contains(Terminators, Tok))
- Terminated = true;
- End = Tok.getEndLoc();
- break;
- }
- }
-
- do {
- // Lex the next token we want to possibly expand the range with.
- Lexer->LexFromRawLexer(Tok);
-
- switch (Tok.getKind()) {
- case tok::unknown:
- if (startsWithNewline(SM, Tok))
- // We're done, but include this newline.
- return Tok.getEndLoc();
- break;
- case tok::comment:
- // Include any comments we find on the way.
- End = Tok.getEndLoc();
- break;
- case tok::semi:
- case tok::comma:
- if (TerminatedByMacro && contains(Terminators, Tok)) {
- End = Tok.getEndLoc();
- // We've found a real terminator.
- TerminatedByMacro = false;
- break;
- }
- // Found an unrelated token; stop and don't include it.
- return End;
- default:
- // Found an unrelated token; stop and don't include it.
- return End;
- }
- } while (true);
-}
-
-// Returns the expected terminator tokens for the given declaration.
-//
-// If we do not know the correct terminator token, returns an empty set.
-//
-// There are cases where we have more than one possible terminator (for example,
-// we find either a comma or a semicolon after a VarDecl).
-static std::set<tok::TokenKind> getTerminators(const Decl &D) {
- if (llvm::isa<RecordDecl>(D) || llvm::isa<UsingDecl>(D))
- return {tok::semi};
-
- if (llvm::isa<FunctionDecl>(D) || llvm::isa<LinkageSpecDecl>(D))
- return {tok::r_brace, tok::semi};
-
- if (llvm::isa<VarDecl>(D) || llvm::isa<FieldDecl>(D))
- return {tok::comma, tok::semi};
-
- return {};
-}
-
-// Starting from `Loc`, skips whitespace up to, and including, a single
-// newline. Returns the (exclusive) end of any skipped whitespace (that is, the
-// location immediately after the whitespace).
-static SourceLocation skipWhitespaceAndNewline(const SourceManager &SM,
- SourceLocation Loc,
- const LangOptions &LangOpts) {
- const char *LocChars = SM.getCharacterData(Loc);
- int i = 0;
- while (isHorizontalWhitespace(LocChars[i]))
- ++i;
- if (isVerticalWhitespace(LocChars[i]))
- ++i;
- return Loc.getLocWithOffset(i);
-}
-
-// Is `Loc` separated from any following decl by something meaningful (e.g. an
-// empty line, a comment), ignoring horizontal whitespace? Since this is a
-// heuristic, we return false when in doubt. `Loc` cannot be the first location
-// in the file.
-static bool atOrBeforeSeparation(const SourceManager &SM, SourceLocation Loc,
- const LangOptions &LangOpts) {
- // If the preceding character is a newline, we'll check for an empty line as a
- // separator. However, we can't identify an empty line using tokens, so we
- // analyse the characters. If we try to use tokens, we'll just end up with a
- // whitespace token, whose characters we'd have to analyse anyhow.
- bool Invalid = false;
- const char *LocChars =
- SM.getCharacterData(Loc.getLocWithOffset(-1), &Invalid);
- assert(!Invalid &&
- "Loc must be a valid character and not the first of the source file.");
- if (isVerticalWhitespace(LocChars[0])) {
- for (int i = 1; isWhitespace(LocChars[i]); ++i)
- if (isVerticalWhitespace(LocChars[i]))
- return true;
- }
- // We didn't find an empty line, so lex the next token, skipping past any
- // whitespace we just scanned.
- Token Tok;
- bool Failed = Lexer::getRawToken(Loc, Tok, SM, LangOpts,
- /*IgnoreWhiteSpace=*/true);
- if (Failed)
- // Any text that confuses the lexer seems fair to consider a separation.
- return true;
-
- switch (Tok.getKind()) {
- case tok::comment:
- case tok::l_brace:
- case tok::r_brace:
- case tok::eof:
- return true;
- default:
- return false;
- }
-}
-
-CharSourceRange tooling::getAssociatedRange(const Decl &Decl,
- ASTContext &Context) {
- const SourceManager &SM = Context.getSourceManager();
- const LangOptions &LangOpts = Context.getLangOpts();
- CharSourceRange Range = CharSourceRange::getTokenRange(Decl.getSourceRange());
-
- // First, expand to the start of the template<> declaration if necessary.
- if (const auto *Record = llvm::dyn_cast<CXXRecordDecl>(&Decl)) {
- if (const auto *T = Record->getDescribedClassTemplate())
- if (SM.isBeforeInTranslationUnit(T->getBeginLoc(), Range.getBegin()))
- Range.setBegin(T->getBeginLoc());
- } else if (const auto *F = llvm::dyn_cast<FunctionDecl>(&Decl)) {
- if (const auto *T = F->getDescribedFunctionTemplate())
- if (SM.isBeforeInTranslationUnit(T->getBeginLoc(), Range.getBegin()))
- Range.setBegin(T->getBeginLoc());
- }
-
- // Next, expand the end location past trailing comments to include a potential
- // newline at the end of the decl's line.
- Range.setEnd(
- getEntityEndLoc(SM, Decl.getEndLoc(), getTerminators(Decl), LangOpts));
- Range.setTokenRange(false);
-
- // Expand to include preceeding associated comments. We ignore any comments
- // that are not preceeding the decl, since we've already skipped trailing
- // comments with getEntityEndLoc.
- if (const RawComment *Comment =
- Decl.getASTContext().getRawCommentForDeclNoCache(&Decl))
- // Only include a preceding comment if:
- // * it is *not* separate from the declaration (not including any newline
- // that immediately follows the comment),
- // * the decl *is* separate from any following entity (so, there are no
- // other entities the comment could refer to), and
- // * it is not a IfThisThenThat lint check.
- if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(),
- Range.getBegin()) &&
- !atOrBeforeSeparation(
- SM, skipWhitespaceAndNewline(SM, Comment->getEndLoc(), LangOpts),
- LangOpts) &&
- atOrBeforeSeparation(SM, Range.getEnd(), LangOpts)) {
- const StringRef CommentText = Comment->getRawText(SM);
- if (!CommentText.contains("LINT.IfChange") &&
- !CommentText.contains("LINT.ThenChange"))
- Range.setBegin(Comment->getBeginLoc());
- }
- // Add leading attributes.
- for (auto *Attr : Decl.attrs()) {
- if (Attr->getLocation().isInvalid() ||
- !SM.isBeforeInTranslationUnit(Attr->getLocation(), Range.getBegin()))
- continue;
- Range.setBegin(Attr->getLocation());
-
- // Extend to the left '[[' or '__attribute((' if we saw the attribute,
- // unless it is not a valid location.
- bool Invalid;
- StringRef Source =
- SM.getBufferData(SM.getFileID(Range.getBegin()), &Invalid);
- if (Invalid)
- continue;
- llvm::StringRef BeforeAttr =
- Source.substr(0, SM.getFileOffset(Range.getBegin()));
- llvm::StringRef BeforeAttrStripped = BeforeAttr.rtrim();
-
- for (llvm::StringRef Prefix : {"[[", "__attribute__(("}) {
- // Handle whitespace between attribute prefix and attribute value.
- if (BeforeAttrStripped.endswith(Prefix)) {
- // Move start to start position of prefix, which is
- // length(BeforeAttr) - length(BeforeAttrStripped) + length(Prefix)
- // positions to the left.
- Range.setBegin(Range.getBegin().getLocWithOffset(static_cast<int>(
- -BeforeAttr.size() + BeforeAttrStripped.size() - Prefix.size())));
- break;
- // If we didn't see '[[' or '__attribute' it's probably coming from a
- // macro expansion which is already handled by makeFileCharRange(),
- // below.
- }
- }
- }
-
- // Range.getEnd() is already fully un-expanded by getEntityEndLoc. But,
- // Range.getBegin() may be inside an expansion.
- return Lexer::makeFileCharRange(Range, SM, LangOpts);
-}
diff --git a/clang/unittests/Tooling/SourceCodeTest.cpp b/clang/unittests/Tooling/SourceCodeTest.cpp
index b1d27bec0bc6..9e0d2e2c4274 100644
--- a/clang/unittests/Tooling/SourceCodeTest.cpp
+++ b/clang/unittests/Tooling/SourceCodeTest.cpp
@@ -20,7 +20,6 @@ using namespace clang;
using llvm::Failed;
using llvm::Succeeded;
using llvm::ValueIs;
-using tooling::getAssociatedRange;
using tooling::getExtendedText;
using tooling::getRangeForEdit;
using tooling::getText;
@@ -52,28 +51,6 @@ MATCHER_P(EqualsRange, R, "") {
arg.getBegin() == R.getBegin() && arg.getEnd() == R.getEnd();
}
-MATCHER_P2(EqualsAnnotatedRange, SM, R, "") {
- if (arg.getBegin().isMacroID()) {
- *result_listener << "which starts in a macro";
- return false;
- }
- if (arg.getEnd().isMacroID()) {
- *result_listener << "which ends in a macro";
- return false;
- }
-
- unsigned Begin = SM->getFileOffset(arg.getBegin());
- unsigned End = SM->getFileOffset(arg.getEnd());
-
- *result_listener << "which is [" << Begin << ",";
- if (arg.isTokenRange()) {
- *result_listener << End << "]";
- return Begin == R.Begin && End + 1 == R.End;
- }
- *result_listener << End << ")";
- return Begin == R.Begin && End == R.End;
-}
-
static ::testing::Matcher<CharSourceRange> AsRange(const SourceManager &SM,
llvm::Annotations::Range R) {
return EqualsRange(CharSourceRange::getCharRange(
@@ -81,37 +58,6 @@ static ::testing::Matcher<CharSourceRange> AsRange(const SourceManager &SM,
SM.getLocForStartOfFile(SM.getMainFileID()).getLocWithOffset(R.End)));
}
-// Base class for visitors that expect a single match corresponding to a
-// specific annotated range.
-template <typename T>
-class AnnotatedCodeVisitor : public TestVisitor<T> {
- llvm::Annotations Code;
- int MatchCount = 0;
-
- public:
- AnnotatedCodeVisitor() : Code("$r[[]]") {}
- bool VisitDeclHelper(Decl *Decl) {
- // Only consider explicit declarations.
- if (Decl->isImplicit())
- return true;
-
- ++MatchCount;
- EXPECT_THAT(
- getAssociatedRange(*Decl, *this->Context),
- EqualsAnnotatedRange(&this->Context->getSourceManager(), Code.range("r")))
- << Code.code();
- return true;
- }
-
- bool runOverAnnotated(llvm::StringRef AnnotatedCode) {
- Code = llvm::Annotations(AnnotatedCode);
- MatchCount = 0;
- bool result = this->runOver(Code.code());
- EXPECT_EQ(MatchCount, 1);
- return result;
- }
-};
-
TEST(SourceCodeTest, getText) {
CallsVisitor Visitor;
@@ -180,237 +126,6 @@ TEST(SourceCodeTest, getExtendedText) {
Visitor.runOver("int foo() { return foo() + 3; }");
}
-TEST(SourceCodeTest, getAssociatedRange) {
- struct VarDeclsVisitor : AnnotatedCodeVisitor<VarDeclsVisitor> {
- bool VisitVarDecl(VarDecl *Decl) {
- return VisitDeclHelper(Decl);
- }
- };
- VarDeclsVisitor Visitor;
-
- // Includes semicolon.
- Visitor.runOverAnnotated("$r[[int x = 4;]]");
-
- // Includes newline and semicolon.
- Visitor.runOverAnnotated("$r[[int x = 4;\n]]");
-
- // Includes trailing comments.
- Visitor.runOverAnnotated("$r[[int x = 4; // Comment\n]]");
- Visitor.runOverAnnotated("$r[[int x = 4; /* Comment */\n]]");
-
- // Does *not* include trailing comments when another entity appears between
- // the decl and the comment.
- Visitor.runOverAnnotated("$r[[int x = 4;]] class C {}; // Comment\n");
-
- // Includes attributes.
- Visitor.runOverAnnotated(R"cpp(
- #define ATTR __attribute__((deprecated("message")))
- $r[[ATTR
- int x;]])cpp");
-
- // Includes attributes and comments together.
- Visitor.runOverAnnotated(R"cpp(
- #define ATTR __attribute__((deprecated("message")))
- $r[[ATTR
- // Commment.
- int x;]])cpp");
-}
-
-TEST(SourceCodeTest, getAssociatedRangeClasses) {
- struct RecordDeclsVisitor : AnnotatedCodeVisitor<RecordDeclsVisitor> {
- bool VisitRecordDecl(RecordDecl *Decl) {
- return VisitDeclHelper(Decl);
- }
- };
- RecordDeclsVisitor Visitor;
-
- Visitor.runOverAnnotated("$r[[class A;]]");
- Visitor.runOverAnnotated("$r[[class A {};]]");
-
- // Includes leading template annotation.
- Visitor.runOverAnnotated("$r[[template <typename T> class A;]]");
- Visitor.runOverAnnotated("$r[[template <typename T> class A {};]]");
-}
-
-TEST(SourceCodeTest, getAssociatedRangeClassTemplateSpecializations) {
- struct CXXRecordDeclsVisitor : AnnotatedCodeVisitor<CXXRecordDeclsVisitor> {
- bool VisitCXXRecordDecl(CXXRecordDecl *Decl) {
- return Decl->getTemplateSpecializationKind() !=
- TSK_ExplicitSpecialization ||
- VisitDeclHelper(Decl);
- }
- };
- CXXRecordDeclsVisitor Visitor;
-
- Visitor.runOverAnnotated(R"cpp(
- template <typename T> class A{};
- $r[[template <> class A<int>;]])cpp");
- Visitor.runOverAnnotated(R"cpp(
- template <typename T> class A{};
- $r[[template <> class A<int> {};]])cpp");
-}
-
-TEST(SourceCodeTest, getAssociatedRangeFunctions) {
- struct FunctionDeclsVisitor : AnnotatedCodeVisitor<FunctionDeclsVisitor> {
- bool VisitFunctionDecl(FunctionDecl *Decl) {
- return VisitDeclHelper(Decl);
- }
- };
- FunctionDeclsVisitor Visitor;
-
- Visitor.runOverAnnotated("$r[[int f();]]");
- Visitor.runOverAnnotated("$r[[int f() { return 0; }]]");
- // Includes leading template annotation.
- Visitor.runOverAnnotated("$r[[template <typename T> int f();]]");
- Visitor.runOverAnnotated("$r[[template <typename T> int f() { return 0; }]]");
-}
-
-TEST(SourceCodeTest, getAssociatedRangeMemberTemplates) {
- struct CXXMethodDeclsVisitor : AnnotatedCodeVisitor<CXXMethodDeclsVisitor> {
- bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {
- // Only consider the definition of the template.
- return !Decl->doesThisDeclarationHaveABody() || VisitDeclHelper(Decl);
- }
- };
- CXXMethodDeclsVisitor Visitor;
-
- Visitor.runOverAnnotated(R"cpp(
- template <typename C>
- struct A { template <typename T> int member(T v); };
-
- $r[[template <typename C>
- template <typename T>
- int A<C>::member(T v) { return 0; }]])cpp");
-}
-
-TEST(SourceCodeTest, getAssociatedRangeWithComments) {
- struct VarDeclsVisitor : TestVisitor<VarDeclsVisitor> {
- llvm::Annotations Code;
- int Count;
-
- VarDeclsVisitor() : Code("$r[[]]") {}
- bool VisitVarDecl(VarDecl *Decl) {
- ++Count;
- EXPECT_THAT(
- getAssociatedRange(*Decl, *Context),
- EqualsAnnotatedRange(&Context->getSourceManager(), Code.range("r")))
- << Code.code();
- return true;
- }
-
- bool runOverAnnotated(llvm::StringRef AnnotatedCode) {
- Code = llvm::Annotations(AnnotatedCode);
- Count = 0;
- std::vector<std::string> Args = {"-std=c++11", "-fparse-all-comments"};
- bool result =
- tooling::runToolOnCodeWithArgs(CreateTestAction(), Code.code(), Args);
- EXPECT_EQ(Count, 1) << Code.code();
- return result;
- }
- };
-
- VarDeclsVisitor Visitor;
-
- // Includes leading comments.
- Visitor.runOverAnnotated("$r[[// Comment.\nint x = 4;]]");
- Visitor.runOverAnnotated("$r[[// Comment.\nint x = 4;\n]]");
- Visitor.runOverAnnotated("$r[[/* Comment.*/\nint x = 4;\n]]");
- // ... even if separated by (extra) horizontal whitespace.
- Visitor.runOverAnnotated("$r[[/* Comment.*/ \nint x = 4;\n]]");
-
- // Includes comments even in the presence of trailing whitespace.
- Visitor.runOverAnnotated("$r[[// Comment.\nint x = 4;]] ");
-
-
- // Includes comments when the declaration is followed by the beginning or end
- // of a compound statement.
- Visitor.runOverAnnotated(R"cpp(
- void foo() {
- $r[[/* C */
- int x = 4;
- ]]};)cpp");
- Visitor.runOverAnnotated(R"cpp(
- void foo() {
- $r[[/* C */
- int x = 4;
- ]]{ class Foo {}; }
- })cpp");
-
- // Includes comments inside macros (when decl is in the same macro).
- Visitor.runOverAnnotated(R"cpp(
- #define DECL /* Comment */ int x
- $r[[DECL;]])cpp");
-
- // Does not include comments when only the decl or the comment come from a
- // macro.
- // FIXME: Change code to allow this.
- Visitor.runOverAnnotated(R"cpp(
- #define DECL int x
- // Comment
- $r[[DECL;]])cpp");
- Visitor.runOverAnnotated(R"cpp(
- #define COMMENT /* Comment */
- COMMENT
- $r[[int x;]])cpp");
-
- // Includes multi-line comments.
- Visitor.runOverAnnotated(R"cpp(
- $r[[/* multi
- * line
- * comment
- */
- int x;]])cpp");
- Visitor.runOverAnnotated(R"cpp(
- $r[[// multi
- // line
- // comment
- int x;]])cpp");
-
- // Does not include comments separated by multiple empty lines.
- Visitor.runOverAnnotated("// Comment.\n\n\n$r[[int x = 4;\n]]");
- Visitor.runOverAnnotated("/* Comment.*/\n\n\n$r[[int x = 4;\n]]");
-
- // Does not include comments before a *series* of declarations.
- Visitor.runOverAnnotated(R"cpp(
- // Comment.
- $r[[int x = 4;
- ]]class foo {};)cpp");
-
- // Does not include IfThisThenThat comments
- Visitor.runOverAnnotated("// LINT.IfChange.\n$r[[int x = 4;]]");
- Visitor.runOverAnnotated("// LINT.ThenChange.\n$r[[int x = 4;]]");
-
- // Includes attributes.
- Visitor.runOverAnnotated(R"cpp(
- #define ATTR __attribute__((deprecated("message")))
- $r[[ATTR
- int x;]])cpp");
-
- // Includes attributes and comments together.
- Visitor.runOverAnnotated(R"cpp(
- #define ATTR __attribute__((deprecated("message")))
- $r[[ATTR
- // Commment.
- int x;]])cpp");
-}
-
-TEST(SourceCodeTest, getAssociatedRangeInvalidForPartialExpansions) {
- struct FailingVarDeclsVisitor : TestVisitor<FailingVarDeclsVisitor> {
- FailingVarDeclsVisitor() {}
- bool VisitVarDecl(VarDecl *Decl) {
- EXPECT_TRUE(getAssociatedRange(*Decl, *Context).isInvalid());
- return true;
- }
- };
-
- FailingVarDeclsVisitor Visitor;
- // Should fail because it only includes a part of the expansion.
- std::string Code = R"cpp(
- #define DECL class foo { }; int x
- DECL;)cpp";
- Visitor.runOver(Code);
-}
-
TEST(SourceCodeTest, EditRangeWithMacroExpansionsShouldSucceed) {
// The call expression, whose range we are extracting, includes two macro
// expansions.
More information about the cfe-commits
mailing list