Index: clang-tools-extra/clangd/Diagnostics.cpp =================================================================== --- clang-tools-extra/clangd/Diagnostics.cpp +++ clang-tools-extra/clangd/Diagnostics.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -102,12 +103,18 @@ if (R.getBegin() == R.getEnd() && Loc == R.getBegin()) FallbackRange = halfOpenToRange(M, R); } - if (FallbackRange) - return *FallbackRange; - // If no suitable range is found, just use the token at the location. - auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L); - if (!R.isValid()) // Fall back to location only, let the editor deal with it. - R = CharSourceRange::getCharRange(Loc); + // If we can't get the token at the location, fall back to using the location + // and let the editor deal with it. + auto R = CharSourceRange::getCharRange(Loc); + Token Tok; + if(!Lexer::getRawToken(Loc, Tok, M, L, true)) { + bool IsTokenComment = Tok.isNot(tok::comment); + // If the token at the location is a comment, just use the location. + // Otherwise use the token. + if (!IsTokenComment && FallbackRange) + return *FallbackRange; + else R = CharSourceRange::getTokenRange(Tok.getLocation(), Tok.getEndLoc()); + } return halfOpenToRange(M, R); } Index: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -101,6 +101,7 @@ Annotations Test(R"cpp( namespace test{}; void $decl[[foo]](); + class T{$explicit[[]]$constructor[[T]](int a);}; int main() { $typo[[go\ o]](); @@ -112,8 +113,10 @@ test::$nomembernamespace[[test]]; } )cpp"); + auto TU = TestTU::withCode(Test.code()); + TU.ClangTidyChecks = "-*,google-explicit-constructor"; EXPECT_THAT( - TestTU::withCode(Test.code()).build().getDiagnostics(), + TU.build().getDiagnostics(), ElementsAre( // This range spans lines. AllOf(Diag(Test.range("typo"), @@ -135,7 +138,13 @@ "of type 'const char [4]'"), Diag(Test.range("nomember"), "no member named 'y' in 'Foo'"), Diag(Test.range("nomembernamespace"), - "no member named 'test' in namespace 'test'"))); + "no member named 'test' in namespace 'test'"), + // We make sure here that the entire token is highlighted + AllOf(Diag(Test.range("constructor"), + "single-argument constructors must be marked explicit to " + "avoid unintentional implicit conversions"), + WithFix(Fix(Test.range("explicit"), "explicit ", + "insert 'explicit '"))))); } TEST(DiagnosticsTest, FlagsMatter) {