Skip to content

Commit

Permalink
[clang-format] Add TypeNames option to disambiguate types/objects
Browse files Browse the repository at this point in the history
If a non-keyword identifier is found in TypeNames, then a *, &, or && that
follows it is annotated as TT_PointerOrReference.

Differential Revision: https://reviews.llvm.org/D155273
  • Loading branch information
owenca committed Jul 18, 2023
1 parent a060102 commit 5c106f7
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 2 deletions.
9 changes: 9 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5355,6 +5355,15 @@ the configuration (without a prefix: ``Auto``).
**TabWidth** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`<TabWidth>`
The number of columns used for tab stops.

.. _TypeNames:

**TypeNames** (``List of Strings``) :versionbadge:`clang-format 17` :ref:`<TypeNames>`
A vector of non-keyword identifiers that should be interpreted as type
names.

A `*`, `&`, or `&&` between a type name and another non-keyword identifier
is annotated as a pointer or reference token instead of a binary operator.

.. _TypenameMacros:

**TypenameMacros** (``List of Strings``) :versionbadge:`clang-format 9` :ref:`<TypenameMacros>`
Expand Down
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@ clang-format
the indentation level of the contents of braced init lists.
- Add ``KeepEmptyLinesAtEOF`` to keep empty lines at end of file.
- Add ``RemoveParentheses`` to remove redundant parentheses.
- Add ``TypeNames`` to treat listed non-keyword identifiers as type names.

libclang
--------
Expand Down
12 changes: 11 additions & 1 deletion clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -4265,6 +4265,15 @@ struct FormatStyle {
/// \version 3.7
unsigned TabWidth;

/// A vector of non-keyword identifiers that should be interpreted as type
/// names.
///
/// A `*`, `&`, or `&&` between a type name and another non-keyword identifier
/// is annotated as a pointer or reference token instead of a binary operator.
///
/// \version 17
std::vector<std::string> TypeNames;

/// \brief A vector of macros that should be interpreted as type declarations
/// instead of as function calls.
///
Expand Down Expand Up @@ -4492,7 +4501,8 @@ struct FormatStyle {
Standard == R.Standard &&
StatementAttributeLikeMacros == R.StatementAttributeLikeMacros &&
StatementMacros == R.StatementMacros && TabWidth == R.TabWidth &&
TypenameMacros == R.TypenameMacros && UseTab == R.UseTab &&
TypeNames == R.TypeNames && TypenameMacros == R.TypenameMacros &&
UseTab == R.UseTab &&
VerilogBreakBetweenInstancePorts ==
R.VerilogBreakBetweenInstancePorts &&
WhitespaceSensitiveMacros == R.WhitespaceSensitiveMacros;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,7 @@ template <> struct MappingTraits<FormatStyle> {
Style.StatementAttributeLikeMacros);
IO.mapOptional("StatementMacros", Style.StatementMacros);
IO.mapOptional("TabWidth", Style.TabWidth);
IO.mapOptional("TypeNames", Style.TypeNames);
IO.mapOptional("TypenameMacros", Style.TypenameMacros);
IO.mapOptional("UseTab", Style.UseTab);
IO.mapOptional("VerilogBreakBetweenInstancePorts",
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ namespace format {
TYPE(TrailingReturnArrow) \
TYPE(TrailingUnaryOperator) \
TYPE(TypeDeclarationParen) \
TYPE(TypeName) \
TYPE(TypenameMacro) \
TYPE(UnaryOperator) \
TYPE(UnionLBrace) \
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ FormatTokenLexer::FormatTokenLexer(
auto Identifier = &IdentTable.get(StatementAttributeLikeMacro);
Macros.insert({Identifier, TT_StatementAttributeLikeMacro});
}

for (const auto &TypeName : Style.TypeNames)
TypeNames.insert(&IdentTable.get(TypeName));
}

ArrayRef<FormatToken *> FormatTokenLexer::lex() {
Expand Down Expand Up @@ -1222,7 +1225,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
}

if (Style.isCpp()) {
auto it = Macros.find(FormatTok->Tok.getIdentifierInfo());
auto *Identifier = FormatTok->Tok.getIdentifierInfo();
auto it = Macros.find(Identifier);
if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_define) &&
Expand All @@ -1240,6 +1244,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
FormatTok->setType(TT_MacroBlockBegin);
else if (MacroBlockEndRegex.match(Text))
FormatTok->setType(TT_MacroBlockEnd);
else if (TypeNames.contains(Identifier))
FormatTok->setFinalizedType(TT_TypeName);
}
}

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/FormatTokenLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Regex.h"

Expand Down Expand Up @@ -126,6 +127,8 @@ class FormatTokenLexer {

llvm::SmallMapVector<IdentifierInfo *, TokenType, 8> Macros;

llvm::SmallPtrSet<IdentifierInfo *, 8> TypeNames;

bool FormattingDisabled;

llvm::Regex MacroBlockBeginRegex;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ class AnnotatingParser {
FormatToken *PrevPrev = Prev->getPreviousNonComment();
FormatToken *Next = CurrentToken->Next;
if (PrevPrev && PrevPrev->is(tok::identifier) &&
PrevPrev->isNot(TT_TypeName) &&
Prev->isOneOf(tok::star, tok::amp, tok::ampamp) &&
CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) {
Prev->setType(TT_BinaryOperator);
Expand Down Expand Up @@ -2508,6 +2509,8 @@ class AnnotatingParser {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
if (!PrevToken)
return TT_UnaryOperator;
if (PrevToken->is(TT_TypeName))
return TT_PointerOrReference;

const FormatToken *NextToken = Tok.getNextNonComment();

Expand Down
13 changes: 13 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,19 @@ TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmp) {
Tokens = annotate("template <enable_if_t<foo && !bar>* = nullptr> void f();");
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
EXPECT_TOKEN(Tokens[5], tok::ampamp, TT_BinaryOperator);

FormatStyle Style = getLLVMStyle();
Style.TypeNames.push_back("MYI");
Tokens = annotate("if (MYI *p{nullptr})", Style);
ASSERT_EQ(Tokens.size(), 10u) << Tokens;
EXPECT_TOKEN(Tokens[2], tok::identifier, TT_TypeName);
EXPECT_TOKEN(Tokens[3], tok::star, TT_PointerOrReference);

Style.TypeNames.push_back("Class");
Tokens = annotate("if (Class *obj {getObj()})", Style);
ASSERT_EQ(Tokens.size(), 12u) << Tokens;
EXPECT_TOKEN(Tokens[2], tok::identifier, TT_TypeName);
EXPECT_TOKEN(Tokens[3], tok::star, TT_PointerOrReference);
}

TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) {
Expand Down

0 comments on commit 5c106f7

Please sign in to comment.