clang 22.0.0git
SourceExtraction.cpp
Go to the documentation of this file.
1//===--- SourceExtraction.cpp - Clang refactoring library -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "clang/AST/Stmt.h"
11#include "clang/AST/StmtCXX.h"
12#include "clang/AST/StmtObjC.h"
14#include "clang/Lex/Lexer.h"
15#include <optional>
16
17using namespace clang;
18
19namespace {
20
21/// Returns true if the token at the given location is a semicolon.
22bool isSemicolonAtLocation(SourceLocation TokenLoc, const SourceManager &SM,
23 const LangOptions &LangOpts) {
25 CharSourceRange::getTokenRange(TokenLoc, TokenLoc), SM,
26 LangOpts) == ";";
27}
28
29/// Returns true if there should be a semicolon after the given statement.
30bool isSemicolonRequiredAfter(const Stmt *S) {
31 if (isa<CompoundStmt>(S))
32 return false;
33 if (const auto *If = dyn_cast<IfStmt>(S))
34 return isSemicolonRequiredAfter(If->getElse() ? If->getElse()
35 : If->getThen());
36 if (const auto *While = dyn_cast<WhileStmt>(S))
37 return isSemicolonRequiredAfter(While->getBody());
38 if (const auto *For = dyn_cast<ForStmt>(S))
39 return isSemicolonRequiredAfter(For->getBody());
40 if (const auto *CXXFor = dyn_cast<CXXForRangeStmt>(S))
41 return isSemicolonRequiredAfter(CXXFor->getBody());
42 if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(S))
43 return isSemicolonRequiredAfter(ObjCFor->getBody());
44 if(const auto *Switch = dyn_cast<SwitchStmt>(S))
45 return isSemicolonRequiredAfter(Switch->getBody());
46 if(const auto *Case = dyn_cast<SwitchCase>(S))
47 return isSemicolonRequiredAfter(Case->getSubStmt());
48 switch (S->getStmtClass()) {
49 case Stmt::DeclStmtClass:
50 case Stmt::CXXTryStmtClass:
51 case Stmt::ObjCAtSynchronizedStmtClass:
52 case Stmt::ObjCAutoreleasePoolStmtClass:
53 case Stmt::ObjCAtTryStmtClass:
54 return false;
55 default:
56 return true;
57 }
58}
59
60/// Returns true if the two source locations are on the same line.
61bool areOnSameLine(SourceLocation Loc1, SourceLocation Loc2,
62 const SourceManager &SM) {
63 return !Loc1.isMacroID() && !Loc2.isMacroID() &&
64 SM.getSpellingLineNumber(Loc1) == SM.getSpellingLineNumber(Loc2);
65}
66
67} // end anonymous namespace
68
69namespace clang {
70namespace tooling {
71
74 const SourceManager &SM,
75 const LangOptions &LangOpts) {
76 auto neededInExtractedFunction = []() {
77 return ExtractionSemicolonPolicy(true, false);
78 };
79 auto neededInOriginalFunction = []() {
80 return ExtractionSemicolonPolicy(false, true);
81 };
82
83 /// The extracted expression should be terminated with a ';'. The call to
84 /// the extracted function will replace this expression, so it won't need
85 /// a terminating ';'.
86 if (isa<Expr>(S))
87 return neededInExtractedFunction();
88
89 /// Some statements don't need to be terminated with ';'. The call to the
90 /// extracted function will be a standalone statement, so it should be
91 /// terminated with a ';'.
92 bool NeedsSemi = isSemicolonRequiredAfter(S);
93 if (!NeedsSemi)
94 return neededInOriginalFunction();
95
96 /// Some statements might end at ';'. The extraction will move that ';', so
97 /// the call to the extracted function should be terminated with a ';'.
98 SourceLocation End = ExtractedRange.getEnd();
99 if (isSemicolonAtLocation(End, SM, LangOpts))
100 return neededInOriginalFunction();
101
102 /// Other statements should generally have a trailing ';'. We can try to find
103 /// it and move it together it with the extracted code.
104 std::optional<Token> NextToken = Lexer::findNextToken(End, SM, LangOpts);
105 if (NextToken && NextToken->is(tok::semi) &&
106 areOnSameLine(NextToken->getLocation(), End, SM)) {
107 ExtractedRange.setEnd(NextToken->getLocation());
108 return neededInOriginalFunction();
109 }
110
111 /// Otherwise insert semicolons in both places.
112 return ExtractionSemicolonPolicy(true, true);
113}
114
115} // end namespace tooling
116} // end namespace clang
#define SM(sm)
Defines the SourceManager interface.
Defines the Objective-C statement AST node classes.
static CharSourceRange getTokenRange(SourceRange R)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Definition Lexer.cpp:1020
static std::optional< Token > findNextToken(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts, bool IncludeComments=false)
Finds the token that comes right after the given location.
Definition Lexer.cpp:1321
Encodes a location in the source.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
void setEnd(SourceLocation e)
Stmt - This represents one statement.
Definition Stmt.h:85
StmtClass getStmtClass() const
Definition Stmt.h:1472
Determines which semicolons should be inserted during extraction.
static ExtractionSemicolonPolicy compute(const Stmt *S, SourceRange &ExtractedRange, const SourceManager &SM, const LangOptions &LangOpts)
Returns the semicolon insertion policy that is needed for extraction of the given statement from the ...
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ If
'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...