Skip to content

Commit 9d34f45

Browse files
committed
[clangd] Show better message when we rename macros.
Summary: Previously, when we rename a macro, we get an error message of "there is no symbol found". This patch improves the message of this case (as we don't support macros). Reviewers: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D63922 llvm-svn: 364735
1 parent d4097b4 commit 9d34f45

File tree

6 files changed

+105
-64
lines changed

6 files changed

+105
-64
lines changed

clang-tools-extra/clangd/SourceCode.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/Basic/TokenKinds.h"
1717
#include "clang/Format/Format.h"
1818
#include "clang/Lex/Lexer.h"
19+
#include "clang/Lex/Preprocessor.h"
1920
#include "llvm/ADT/None.h"
2021
#include "llvm/ADT/StringExtras.h"
2122
#include "llvm/ADT/StringRef.h"
@@ -653,5 +654,31 @@ llvm::StringSet<> collectWords(llvm::StringRef Content) {
653654
return Result;
654655
}
655656

657+
llvm::Optional<DefinedMacro> locateMacroAt(SourceLocation Loc,
658+
Preprocessor &PP) {
659+
const auto &SM = PP.getSourceManager();
660+
const auto &LangOpts = PP.getLangOpts();
661+
Token Result;
662+
if (Lexer::getRawToken(SM.getSpellingLoc(Loc), Result, SM, LangOpts, false))
663+
return None;
664+
if (Result.is(tok::raw_identifier))
665+
PP.LookUpIdentifierInfo(Result);
666+
IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
667+
if (!IdentifierInfo || !IdentifierInfo->hadMacroDefinition())
668+
return None;
669+
670+
std::pair<FileID, unsigned int> DecLoc = SM.getDecomposedExpansionLoc(Loc);
671+
// Get the definition just before the searched location so that a macro
672+
// referenced in a '#undef MACRO' can still be found.
673+
SourceLocation BeforeSearchedLocation =
674+
SM.getMacroArgExpandedLocation(SM.getLocForStartOfFile(DecLoc.first)
675+
.getLocWithOffset(DecLoc.second - 1));
676+
MacroDefinition MacroDef =
677+
PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
678+
if (auto *MI = MacroDef.getMacroInfo())
679+
return DefinedMacro{IdentifierInfo->getName(), MI};
680+
return None;
681+
}
682+
656683
} // namespace clangd
657684
} // namespace clang

clang-tools-extra/clangd/SourceCode.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ llvm::StringSet<> collectWords(llvm::StringRef Content);
201201
std::vector<std::string> visibleNamespaces(llvm::StringRef Code,
202202
const format::FormatStyle &Style);
203203

204+
struct DefinedMacro {
205+
llvm::StringRef Name;
206+
const MacroInfo *Info;
207+
};
208+
// Gets the macro at a specified \p Loc.
209+
llvm::Optional<DefinedMacro> locateMacroAt(SourceLocation Loc,
210+
Preprocessor &PP);
211+
204212
} // namespace clangd
205213
} // namespace clang
206214
#endif

clang-tools-extra/clangd/XRefs.cpp

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,9 @@ SymbolLocation getPreferredLocation(const Location &ASTLoc,
128128
return Merged.CanonicalDeclaration;
129129
}
130130

131-
struct MacroDecl {
132-
llvm::StringRef Name;
133-
const MacroInfo *Info;
134-
};
135-
136131
/// Finds declarations locations that a given source location refers to.
137132
class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
138-
std::vector<MacroDecl> MacroInfos;
133+
std::vector<DefinedMacro> MacroInfos;
139134
llvm::DenseSet<const Decl *> Decls;
140135
const SourceLocation &SearchedLocation;
141136
const ASTContext &AST;
@@ -158,16 +153,18 @@ class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
158153
return Result;
159154
}
160155

161-
std::vector<MacroDecl> takeMacroInfos() {
156+
std::vector<DefinedMacro> takeMacroInfos() {
162157
// Don't keep the same Macro info multiple times.
163-
llvm::sort(MacroInfos, [](const MacroDecl &Left, const MacroDecl &Right) {
164-
return Left.Info < Right.Info;
165-
});
166-
167-
auto Last = std::unique(MacroInfos.begin(), MacroInfos.end(),
168-
[](const MacroDecl &Left, const MacroDecl &Right) {
169-
return Left.Info == Right.Info;
170-
});
158+
llvm::sort(MacroInfos,
159+
[](const DefinedMacro &Left, const DefinedMacro &Right) {
160+
return Left.Info < Right.Info;
161+
});
162+
163+
auto Last =
164+
std::unique(MacroInfos.begin(), MacroInfos.end(),
165+
[](const DefinedMacro &Left, const DefinedMacro &Right) {
166+
return Left.Info == Right.Info;
167+
});
171168
MacroInfos.erase(Last, MacroInfos.end());
172169
return std::move(MacroInfos);
173170
}
@@ -211,38 +208,16 @@ class DeclarationAndMacrosFinder : public index::IndexDataConsumer {
211208

212209
private:
213210
void finish() override {
214-
// Also handle possible macro at the searched location.
215-
Token Result;
216-
auto &Mgr = AST.getSourceManager();
217-
if (!Lexer::getRawToken(Mgr.getSpellingLoc(SearchedLocation), Result, Mgr,
218-
AST.getLangOpts(), false)) {
219-
if (Result.is(tok::raw_identifier)) {
220-
PP.LookUpIdentifierInfo(Result);
221-
}
222-
IdentifierInfo *IdentifierInfo = Result.getIdentifierInfo();
223-
if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
224-
std::pair<FileID, unsigned int> DecLoc =
225-
Mgr.getDecomposedExpansionLoc(SearchedLocation);
226-
// Get the definition just before the searched location so that a macro
227-
// referenced in a '#undef MACRO' can still be found.
228-
SourceLocation BeforeSearchedLocation = Mgr.getMacroArgExpandedLocation(
229-
Mgr.getLocForStartOfFile(DecLoc.first)
230-
.getLocWithOffset(DecLoc.second - 1));
231-
MacroDefinition MacroDef =
232-
PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation);
233-
MacroInfo *MacroInf = MacroDef.getMacroInfo();
234-
if (MacroInf) {
235-
MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf});
236-
assert(Decls.empty());
237-
}
238-
}
211+
if (auto DefinedMacro = locateMacroAt(SearchedLocation, PP)) {
212+
MacroInfos.push_back(*DefinedMacro);
213+
assert(Decls.empty());
239214
}
240215
}
241216
};
242217

243218
struct IdentifiedSymbol {
244219
std::vector<const Decl *> Decls;
245-
std::vector<MacroDecl> Macros;
220+
std::vector<DefinedMacro> Macros;
246221
};
247222

248223
IdentifiedSymbol getSymbolAtPosition(ParsedAST &AST, SourceLocation Pos) {
@@ -740,18 +715,18 @@ static HoverInfo getHoverContents(QualType T, const Decl *D,
740715
}
741716

742717
/// Generate a \p Hover object given the macro \p MacroDecl.
743-
static HoverInfo getHoverContents(MacroDecl Decl, ParsedAST &AST) {
718+
static HoverInfo getHoverContents(const DefinedMacro &Macro, ParsedAST &AST) {
744719
HoverInfo HI;
745720
SourceManager &SM = AST.getSourceManager();
746-
HI.Name = Decl.Name;
721+
HI.Name = Macro.Name;
747722
HI.Kind = indexSymbolKindToSymbolKind(
748-
index::getSymbolInfoForMacro(*Decl.Info).Kind);
723+
index::getSymbolInfoForMacro(*Macro.Info).Kind);
749724
// FIXME: Populate documentation
750725
// FIXME: Pupulate parameters
751726

752727
// Try to get the full definition, not just the name
753-
SourceLocation StartLoc = Decl.Info->getDefinitionLoc();
754-
SourceLocation EndLoc = Decl.Info->getDefinitionEndLoc();
728+
SourceLocation StartLoc = Macro.Info->getDefinitionLoc();
729+
SourceLocation EndLoc = Macro.Info->getDefinitionEndLoc();
755730
if (EndLoc.isValid()) {
756731
EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM,
757732
AST.getASTContext().getLangOpts());

clang-tools-extra/clangd/refactor/Rename.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,25 @@ llvm::Optional<ReasonToReject> renamableWithinFile(const Decl &RenameDecl,
136136
return ReasonToReject::UsedOutsideFile;
137137
}
138138

139+
llvm::Error makeError(ReasonToReject Reason) {
140+
auto Message = [](ReasonToReject Reason) {
141+
switch (Reason) {
142+
case NoIndexProvided:
143+
return "symbol may be used in other files (no index available)";
144+
case UsedOutsideFile:
145+
return "the symbol is used outside main file";
146+
case NonIndexable:
147+
return "symbol may be used in other files (not eligible for indexing)";
148+
case UnsupportedSymbol:
149+
return "symbol is not a supported kind (e.g. namespace, macro)";
150+
}
151+
llvm_unreachable("unhandled reason kind");
152+
};
153+
return llvm::make_error<llvm::StringError>(
154+
llvm::formatv("Cannot rename symbol: {0}", Message(Reason)),
155+
llvm::inconvertibleErrorCode());
156+
}
157+
139158
} // namespace
140159

141160
llvm::Expected<tooling::Replacements>
@@ -145,6 +164,10 @@ renameWithinFile(ParsedAST &AST, llvm::StringRef File, Position Pos,
145164
ASTContext &ASTCtx = AST.getASTContext();
146165
SourceLocation SourceLocationBeg = clangd::getBeginningOfIdentifier(
147166
AST, Pos, AST.getSourceManager().getMainFileID());
167+
// FIXME: renaming macros is not supported yet, the macro-handling code should
168+
// be moved to rename tooling library.
169+
if (locateMacroAt(SourceLocationBeg, AST.getPreprocessor()))
170+
return makeError(UnsupportedSymbol);
148171
tooling::RefactoringRuleContext Context(AST.getSourceManager());
149172
Context.setASTContext(ASTCtx);
150173
auto Rename = clang::tooling::RenameOccurrences::initiate(
@@ -155,24 +178,8 @@ renameWithinFile(ParsedAST &AST, llvm::StringRef File, Position Pos,
155178
const auto *RenameDecl = Rename->getRenameDecl();
156179
assert(RenameDecl && "symbol must be found at this point");
157180
if (auto Reject =
158-
renamableWithinFile(*RenameDecl->getCanonicalDecl(), File, Index)) {
159-
auto Message = [](ReasonToReject Reason) {
160-
switch (Reason) {
161-
case NoIndexProvided:
162-
return "symbol may be used in other files (no index available)";
163-
case UsedOutsideFile:
164-
return "the symbol is used outside main file";
165-
case NonIndexable:
166-
return "symbol may be used in other files (not eligible for indexing)";
167-
case UnsupportedSymbol:
168-
return "symbol is not a supported kind (e.g. namespace)";
169-
}
170-
llvm_unreachable("unhandled reason kind");
171-
};
172-
return llvm::make_error<llvm::StringError>(
173-
llvm::formatv("Cannot rename symbol: {0}", Message(*Reject)),
174-
llvm::inconvertibleErrorCode());
175-
}
181+
renamableWithinFile(*RenameDecl->getCanonicalDecl(), File, Index))
182+
return makeError(*Reject);
176183

177184
Rename->invoke(ResultCollector, Context);
178185

clang-tools-extra/clangd/unittests/RenameTests.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ TEST(RenameTest, Renameable) {
129129
)cpp",
130130
"not a supported kind", HeaderFile},
131131

132+
{
133+
R"cpp(
134+
#define MACRO 1
135+
int s = MAC^RO;
136+
)cpp",
137+
"not a supported kind", HeaderFile},
138+
132139
{R"cpp(// foo is declared outside the file.
133140
void fo^o() {}
134141
)cpp", "used outside main file", !HeaderFile/*cc file*/},

clang-tools-extra/clangd/unittests/SourceCodeTests.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Context.h"
1010
#include "Protocol.h"
1111
#include "SourceCode.h"
12+
#include "TestTU.h"
1213
#include "clang/Format/Format.h"
1314
#include "llvm/Support/Error.h"
1415
#include "llvm/Support/raw_os_ostream.h"
@@ -28,6 +29,8 @@ MATCHER_P2(Pos, Line, Col, "") {
2829
return arg.line == int(Line) && arg.character == int(Col);
2930
}
3031

32+
MATCHER_P(MacroName, Name, "") { return arg.Name == Name; }
33+
3134
/// A helper to make tests easier to read.
3235
Position position(int line, int character) {
3336
Position Pos;
@@ -404,6 +407,20 @@ TEST(SourceCodeTests, VisibleNamespaces) {
404407
}
405408
}
406409

410+
TEST(SourceCodeTests, GetMacros) {
411+
Annotations Code(R"cpp(
412+
#define MACRO 123
413+
int abc = MA^CRO;
414+
)cpp");
415+
TestTU TU = TestTU::withCode(Code.code());
416+
auto AST = TU.build();
417+
auto Loc = getBeginningOfIdentifier(AST, Code.point(),
418+
AST.getSourceManager().getMainFileID());
419+
auto Result = locateMacroAt(Loc, AST.getPreprocessor());
420+
ASSERT_TRUE(Result);
421+
EXPECT_THAT(*Result, MacroName("MACRO"));
422+
}
423+
407424
} // namespace
408425
} // namespace clangd
409426
} // namespace clang

0 commit comments

Comments
 (0)