diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/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,11 +103,21 @@ 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. + // If the token at location is not a comment, use the token. + // Otherwise use zero width insertion range auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L); - if (!R.isValid()) // Fall back to location only, let the editor deal with it. + if (R.isValid()) { + // check if token at location is a priority i.e. not a comment + Token token; + bool isTokenPriority = false; + if(!Lexer::getRawToken(Loc, token, M, L, true)) + isTokenPriority = token.getKind() != tok::comment; + if (!isTokenPriority && FallbackRange) + return *FallbackRange; + } + else if (FallbackRange) + return *FallbackRange; + else // Fall back to location only, let the editor deal with it. R = CharSourceRange::getCharRange(Loc); return halfOpenToRange(M, R); } diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -1,3 +1,4 @@ + //===--- DiagnosticsTests.cpp ------------------------------------*- C++-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -101,6 +102,7 @@ Annotations Test(R"cpp( namespace test{}; void $decl[[foo]](); + class T{$explicit[[]]$constructor[[T]](int a);}; int main() { $typo[[go\ o]](); @@ -112,8 +114,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 +139,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) {